为什么在表达式树中需要转换

从5分钟前我问过这个问题 ,很明显以下代码会引发exception,说明这一点

未处理的exception:System.InvalidOperationException:没有为类型’System.Nullable`1 [System.Int32]’和’System.Int32’定义二进制运算符Equal。

public static void GetResultCollection() { AccrualTrackingEntities db = new AccrualTrackingEntities(); var result = db.CreateQuery(String.Format("[{0}]", typeof(T).Name + "s")); int? ItemTypeValue = 1; var param = Expression.Parameter(typeof(T)); var lambda = Expression.Lambda<Func>( Expression.Equal( Expression.Property(param, "ProcInstId"), Expression.Constant(ItemTypeValue)), param); var list = result.Where(lambda).ToList(); } 

但是,此代码与Expression.Constant中明确列出的类型确实有效

 class Program { public static void GetResultCollection() { AccrualTrackingEntities db = new AccrualTrackingEntities(); var result = db.CreateQuery(String.Format("[{0}]", typeof(T).Name + "s")); int? ItemTypeValue = 1; var param = Expression.Parameter(typeof(T)); var lambda = Expression.Lambda<Func>( Expression.Equal( Expression.Property(param, "ProcInstId"), Expression.Constant(ItemTypeValue, typeof(int?))), param); var list = result.Where(lambda).ToList(); } 

问题是, 为什么 Expression.Constant无法从int?隐式转换int? 到… int?

表达式树在较低级别上工作到正常的源代码 – 您可以将它们视为在编译器输出级别而不是输入级别工作。 那么虽然从intint?的隐式转换int? 在C#中,只要编译器将其用于普通方法,就必须在IL中表示转换…因此它也必须存在于表达式树表示中。

说到这一点,你的例子有点不清楚,因为你试图使用int (即ItemTypeValue.Value )作为int?的值int? 常量,我们不知道ItemType属性的类型是什么。

您期望工作的一个简短而完整的例子真的会有所帮助。

编辑:好的,我想我现在和你在一起。 问题是,如果你使用

 int? foo = 1; Expression.Constant(foo); 

然后调用Expression.Constant(object)foo值的Expression.Constant(object) 。 那时, Expression.Constant不能告诉它原来是一个int? ,因为它现在是一个盒装的int 。 这就是.NET拳击的工作方式:

 int? foo = 1; object o = foo; Console.WriteLine(o.GetType()); // Prints System.Int32 

Expression.Constant重载从它给出的值确定Expression.Constant的整体类型 – 所以它创建一个int表达式,而你真的想要一个int? 表达。

为了正确维护类型信息,您必须使用允许您指定类型的重载:

 int? foo = 1; Expression.Constant(foo, typeof(int?)); 

你的问题仍然不完全清楚哪些代码有效,哪些代码无效,但希望这有助于……