Expression.Equal - Как да сравняваме Nullable и Non Nullable полета?

Имам nullable datetime поле и трябва да преобразувам string полето за дата в nullable тип datetime (с помощта на Expression).... Направих това, използвайки по-долу.

 Expression.Constant(Convert.ChangeType(value, Nullable.GetUnderlyingType(memberAccess.Type)));.

MemberAccess (споменат по-горе) е от тип член израз. (От LinqExtensions.cs) Сега в кода използвам метод Expression.Equal.

Expression.Equal(memberAccess, filter); 

Тук това се проваля, тъй като типът memberaccess е nullable, но filter.type не е nullable...

Дори ако се опитам да преобразувам типа достъп на член в nullable с помощта

ConstantExpression test = Expression.Constant(Nullable.GetUnderlyingType(memberAccess.Type)),

Типът е Runtime, а не DateTime.

Как да използвам Expression.Equal за сравняване на nullable и non nullable поле? Има ли някакъв начин да преобразувате типа низ в поле за дата и час с nullable? Всяко едно от тези неща ще разреши проблема ми.


person user2325247    schedule 17.05.2013    source източник
comment
Публикувайте част от вашия код тук.   -  person Vond Ritz    schedule 17.05.2013
comment
Имате ли ограничение, че трябва да използвате САМО Expression?   -  person jacob aloysious    schedule 17.05.2013


Отговори (3)


Добре.. направих по този начин.

Първо преобразува типа (низ в datetime)

filter = Expression.Constant(
    Convert.ChangeType(value, memberAccess.Type.GetGenericArguments()[0]));

след това преобразува този израз в желания тип

Expression typeFilter = Expression.Convert(filter, memberAccess.Type);

След това се използва Expression.Equal(memberAccess, typeFilter)...

(memberAccess is MemberExpression и взема типа свойство от модела)

person user2325247    schedule 17.05.2013

Ако имате стойности Nullable стойности, различни от дати, Ето как можете да създадете дърво на изрази за nullable типове, да предположим, че имате nullable поле BoardId, можете да създадете дърво на изрази динамично по този начин

var nameValue="BoardId=111";

 public static Expression<Func<T, bool>> BuildWhereExpression<T>(string nameValueQuery ) where  T : class 
        {
            Expression<Func<T, bool>> predicate = null;
            PropertyInfo prop = null;
            var fieldName = nameValueQuery.Split("=")[0];
            var fieldValue = nameValueQuery.Split("=")[1];
            var properties = typeof(T).GetProperties();
            foreach (var property in properties)
            {
                if (property.Name.ToLower() == fieldName.ToLower())
                {
                    prop = property;
                }
            } 
            if (prop != null)
            {
                var isNullable = prop.PropertyType.IsNullableType();
                var parameter = Expression.Parameter(typeof(T), "x");
                var member = Expression.Property(parameter, fieldName); 

                if (isNullable)
                {
                    var filter1 =
                        Expression.Constant(
                            Convert.ChangeType(fieldValue, member.Type.GetGenericArguments()[0]));
                    Expression typeFilter = Expression.Convert(filter1, member.Type);
                    var body = Expression.Equal(member, typeFilter);  
                    predicate = Expression.Lambda<Func<T, bool>>(body, parameter);  
                }
                else
                {
                    if (prop.PropertyType == typeof(string) && likeOerator.ToLower() == "like")
                    {
                        var parameterExp = Expression.Parameter(typeof(T), "type");
                        var propertyExp = Expression.Property(parameterExp, prop);
                        MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
                        var someValue = Expression.Constant(fieldValue, typeof(string));
                        var containsMethodExp = Expression.Call(propertyExp, method, someValue);
                        predicate = Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
                    }
                    else
                    {
                        var constant = Expression.Constant(Convert.ChangeType(fieldValue, prop.PropertyType));
                        var body = Expression.Equal(member, constant);  
                        predicate = Expression.Lambda<Func<T, bool>>(body, parameter); `enter code here`
                    }
                }
            }
            return predicate;
        }

1- Това решение първо проверява за стойността Nullable и генерира израза. Ето как можете да определите дали типът е Nullable. Създадох метод за разширение за тази цел

public static bool IsNullableType(this Type type)
    {
        return type.IsGenericType && (type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)));
    }

2- втората стъпка е да проверите типа, ако неговият низ след това създадете израз за низ.

3- Третата стъпка е да проверите дали стойността не е nullable, а не низ, след което създайте израз, използвайки равен

person Aamir    schedule 24.05.2018
comment
Благодаря. Отговори на това: stackoverflow.com/questions/63524188/ - person Diogo Almeida; 21.08.2020

Трябва да използвате DateTime.Parse или, по-добре, DateTime.ParseExact, за да преобразувате вашия низ към днешна дата. И така, Expression.Call.

Ако искате да го конвертирате в null date, ако низът е null, можете да използвате Expression.Condition.
Ако искате да направите резултата nullable, вярвам, че Expression.Convert може да направи това.

Така че нещо като (псевдокод):

Condition(
    Equals(yourStringExpression, null),
    Constant(null, typeof(DateTime?)),
    Convert(
        Call(DateTime.ParseExact, yourStringExpression, ...),
        typeof(DateTime?)
    )
)
person Andrey Shchekin    schedule 17.05.2013