Проблема здесь в том, что библиотека выражений выдает исключение, если дано два аргумента с несовпадающей обнуляемостью.Вот простое повторение:
Expression<Func<DateTime?>> ex1 = ()=>DateTime.Now;
Expression<Func<DateTime>> ex2 = ()=>DateTime.Now;
var ex3 = Expression.GreaterThan(ex1.Body, ex2.Body);
Мне не ясно, является ли это ошибкой или нет;правила в C # требуют, чтобы в этом сценарии необнуляемый операнд был преобразован в обнуляемый, и использовалась форма сравнения с возвратом в нуль. Однако , библиотека дерева выражений не обязана следовать правилам C # , потому что, конечно, библиотека дерева выражений может использоваться для представления выражений C #, выражений Python, выражений JScript, выражений VBи так далее;он не может следовать всем правилам всех возможных языков.
Но независимо от этого, похоже, что это может быть ошибкой, поэтому я отправлю его в команду дерева выражений и посмотрю, что они скажут.В то же время вы можете легко обойти это, определив свой собственный вспомогательный метод, который исправляет операнды.Быстрый набросок будет выглядеть следующим образом:
static Expression MyGreaterThan(Expression e1, Expression e2)
{
if (IsNullableType(e1.Type) && !IsNullableType(e2.Type))
e2 = Expression.Convert(e2, e1.Type);
else if (!IsNullableType(e1.Type) && IsNullableType(e2.Type))
e1 = Expression.Convert(e1, e2.Type);
return Expression.GreaterThan(e1, e2);
}
static bool IsNullableType(Type t)
{
return t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}
Однако обратите внимание, что это не проверяет, что тип e1 и e2 различаются только по обнуляемости;если вы передадите пустое int и ненулевое двойное выражение, произойдут плохие вещи. Я оставляю это в качестве упражнения для реализации лучшей логики, которая проверяет, имеют ли два выражения тип, отличающийся только обнуляемостью.