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

标签 c# entity-framework expression-trees

来自 this question我5分钟前问过,很明显下面的代码抛出异常,说明

Unhandled Exception: System.InvalidOperationException: The binary operator Equal is not defined for the types 'System.Nullable`1[System.Int32]' and 'System.Int32'.

代码

public static void GetResultCollection<T>() {
        AccrualTrackingEntities db = new AccrualTrackingEntities();
        var result = db.CreateQuery<T>(String.Format("[{0}]", typeof(T).Name + "s"));

        int? ItemTypeValue = 1;

        var param = Expression.Parameter(typeof(T));

        var lambda = Expression.Lambda<Func<T, bool>>(
            Expression.Equal(
                Expression.Property(param, "ProcInstId"),
                Expression.Constant(ItemTypeValue)),
            param);

        var list = result.Where(lambda).ToList();
    }

但是,这段代码在 Expression.Constant 中明确列出的类型确实有效

class Program {
    public static void GetResultCollection<T>() {
        AccrualTrackingEntities db = new AccrualTrackingEntities();
        var result = db.CreateQuery<T>(String.Format("[{0}]", typeof(T).Name + "s"));

        int? ItemTypeValue = 1;

        var param = Expression.Parameter(typeof(T));

        var lambda = Expression.Lambda<Func<T, bool>>(
            Expression.Equal(
                Expression.Property(param, "ProcInstId"),
                Expression.Constant(ItemTypeValue, typeof(int?))),
            param);

        var list = result.Where(lambda).ToList();
    }

问题是,为什么 Expression.Constant 不能从 int? 隐式转换为 ... int?

最佳答案

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

话虽如此,鉴于您正尝试使用 int(即 ItemTypeValue.Value)作为 的值,您的示例有些不清楚>int? 常量,我们也不知道 ItemType 属性的类型是什么。

一个简短但完整您期望工作的例子会很有帮助。

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

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

然后调用Expression.Constant(object)其中包含 foo 的值。那时,Expression.Constant 无法判断它原来是一个 int?,因为它现在是一个装箱的 int。这就是 .NET 装箱的工作方式:

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

Expression.Constant 的重载根据给定的值确定表达式的整体类型 - 因此它创建了一个 int 表达式,而你真的想要一个 int? 表达式。

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

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

从您的问题中还不能完全清楚哪些代码有效,哪些无效,但希望这会有所帮助...

关于c# - 为什么在表达式树中需要转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5067486/

相关文章:

linq - 动态构建 Linq 查询

c# - 如何将字典值从 Postman 发布到 .net core 3.1 API

c# - 如何使用 Syncfusion Metro Studio 生成的 XAML 字典

c# - ASP.NET MVC 搜索页面 - Linq + EF4 上的整数 StartsWith

c# - LINQ 左外部联接 - 对象引用未设置为对象的实例

linq - 编译需要参数的表达式

c# - 创建自定义字符串类

c# - Windows 窗体应用程序异常

c# - 通过存储过程将上传的文件(InputStream)保存到SQL Server

c# - 动态为ctor创建委托(delegate)