如果一个操作数是可空类型,则Expression.GreaterThan失败,另一个操作数是非可空的

Ant*_*ain 28 .net c# c#-3.0

我正在创建一些动态linq并遇到以下异常问题:

没有为类型'System.Nullable`1 [System.DateTime]'和'System.DateTime'定义二元运算符GreaterThanOrEqual

我明白了,因为我的字段类型是可以为空的,而且我实际上是在DateTime.Now中传递的.

所以在试图解决这个问题时我已经尝试过了

System.Nullable<DateTime> now;
now = DateTime.Now;
Run Code Online (Sandbox Code Playgroud)

但结果类型是一个不可为空的对象,因此仍然给我上述异常.

有什么建议?!

更新:为了进一步说明,now变量在设置时变为非可空类型,而不是保持为可空的DateTime,因此匹配会引发异常

更新:可以在CodePlex项目中看到实际代码:

http://webquarters.codeplex.com/SourceControl/changeset/view/36529#574700

违规线约为145

fExp = Expression.GreaterThanOrEqual(fExpLeft, fExpRight);
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 57

这里的问题是,当给出两个不匹配的可为空性的参数时,表达式库会抛出异常.这是一个简单的复制品:

Expression<Func<DateTime?>> ex1 = ()=>DateTime.Now;
Expression<Func<DateTime>> ex2 = ()=>DateTime.Now;
var ex3 = Expression.GreaterThan(ex1.Body, ex2.Body);
Run Code Online (Sandbox Code Playgroud)

我不清楚这是不是一个错误; C#的规则要求在这种情况下,非可空操作数转换为可空,并使用提升到可空的比较形式. 但是,表达式树库不需要遵循C#的规则,因为表达式树库当然可以用来表示C#表达式,Python表达式,JScript表达式,VB表达式等等; 它不可能遵循所有可能语言的所有规则.

但无论如何,这看起来可能是一个bug,所以我会将它提交给表达式树队,看看他们说了什么.同时,您可以通过定义自己的辅助方法来轻松解决操作,修复操作数.快速草图将是:

    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<>);
    }
Run Code Online (Sandbox Code Playgroud)

但是,请注意,这并不会检查e1和e2的类型是否仅在可空性方面有所不同; 如果你传入一个可以为空的int和一个不可为空的双重表达式,就会发生不好的事情.我把它留作练习来实现更好的逻辑,检查这两个表达式是否只有可空性的类型.

  • 添加了一些检查的[LINQPad](http://www.linqpad.net/)示例:https://gist.github.com/kappa7194/21c3390130f3e8d54fc2 (2认同)