没有为类型 'System.Int32' 和 'System.Object' 定义二元运算符 Equal

The binary operator Equal is not defined for the types 'System.Int32' and 'System.Object'

我想构建以下表达式:

myObj.Id == null

myObj.Id 是一个不可为空的整数。我知道如果这个表达式按字面意思求值,那么结果总是假的,但我需要构建这个表达式,因为表达式访问者稍后会检查它并用它做一些事情。

完全可以在您的代码中按字面意义编写此表达式,但是当我尝试使用以下工厂方法动态构建它时:

Expression.Equal(left: /* myObj.Id */, right: /* anotherId */);

我得到以下异常:

The binary operator Equal is not defined for the types 'System.Int32' and 'System.Object'.

这没有意义,因为可以在 C# 中直接编写完全相同的表达式。

如何生成该表达式? <int> == null?

How can I generate that expression? == null?

编译器将 int 提升为可空类型,即 Nullable<int>,也称为 int?。你需要做同样的事情。

作为一种通用技术,使用编译器本身向您展示如何构建一个执行您想要的操作的 Expression 对象通常很有帮助。例如,要回答您的特定问题,即如何生成该表达式,只需编写您想要的表达式,编译它,然后 运行 在调试器中将其 运行 以便您可以查看编译器做了什么:

Expression<Func<int, bool>> ex = i => i == null;

如果这样做,您会发现一个 Body 值为 "(Convert(i) == null)" 的表达式。即节点类型为Equal,右操作数为null,左操作数为Convert节点,其操作数为inti,目标类型为 Nullable<int>.

有了这些信息,现在编写实际构建该表达式的 C# 代码应该相对容易了。当然,另一种方法是只使用上面的声明(或类似的东西)并且 always 让编译器为你构建 Expression 对象。如果可以的话,我个人宁愿不写 Expression-building 代码。它非常冗长而且 error-prone,所以任何时候编译器可以为我完成工作(这很常见),我让它去做。