Expression.Equal — как сравнить поля Nullable и Non Nullable?

У меня есть поле datetime с нулевым значением, и мне нужно преобразовать поле даты string в тип даты и времени, допускающий значение NULL (используя Expression).... Я сделал это, используя приведенное ниже.

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

MemberAccess (упомянутый выше) имеет тип выражения члена. (Из LinqExtensions.cs) Теперь в коде я использую метод Expression.Equal.

Expression.Equal(memberAccess, filter); 

Здесь это не работает, так как тип доступа к члену имеет значение NULL, но filter.type не имеет значения NULL...

Даже если я попытаюсь преобразовать тип доступа к члену в nullable, используя

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

Тип — Runtime, а не DateTime.

Как использовать Expression.Equal для сравнения поля, допускающего значение NULL, и поля, не допускающего значение NULL? Есть ли способ преобразовать тип строки в поле даты и времени, допускающее значение NULL? Любой из них решит мою проблему.


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)


Хорошо.. Я сделал так.

Сначала преобразовал тип (строка в дату и время)

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 значения, отличные от дат, вот как вы можете создать дерево выражений для типов, допускающих значение null, предположим, что у вас есть поле BoardId, допускающее значение null, вы можете динамически создавать дерево выражений, как это

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- Третий шаг - проверить, является ли значение не обнуляемым, а не строкой, а затем создать выражение, используя равенство

person Aamir    schedule 24.05.2018
comment
Спасибо. Ответил на это: «как использовать methodinfo и lifttonull в равенстве выражений на C Sharp»> stackoverflow.com/questions/63524188/ - person Diogo Almeida; 21.08.2020

Вы должны использовать DateTime.Parse или, лучше, DateTime.ParseExact для преобразования вашей строки в дату. Итак, Expression.Call.

Если вы хотите преобразовать его в нулевую дату, если строка имеет значение null, вы можете использовать Expression.Condition.
Если вы хотите сделать результат обнуляемым, я считаю, что Expression.Convert может это сделать.

Что-то вроде (псевдокод):

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