【问题标题】:Why is a conversion necessary in Expression Trees为什么在表达式树中需要转换
【发布时间】:2011-02-21 15:01:45
【问题描述】:

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

未处理的异常: System.InvalidOperationException: 二元运算符 Equal 未定义 对于类型 'System.Nullable`1[System.Int32]' 和 '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?

【问题讨论】:

  • 您可以创建自己的扩展,您可以在其中获取类型以及是否可以为空等。然后将 Expression.Constant(Object, Type) 与发现的类型一起使用

标签: c# entity-framework expression-trees


【解决方案1】:

表达式树在正常源代码的较低级别工作 - 您可以将它们视为在编译器的输出级别而不是输入级别工作。因此,尽管在 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?));

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

【讨论】:

  • 好了。我对原始问题的措辞很糟糕。按照我的方式,它确实试图从 int 转换为 int?我最初的问题应该是直接从 int 开始的?到int?
  • 我更改了原始问题的文本,使其更有意义。现在有了 Expression.Constant(ItemValueType, int?) 其中 ItemValueType 被声明为 int? (我认为这是多余的)如果我知道你在附近,我会在发布之前进行三重检查:-)
  • @Adam:你还没有告诉我们“ItemType”的类型是什么。这就是为什么我希望有一个完整的示例——我们可以编译和运行的控制台应用程序。
  • 它是整数?在数据库中,在实体中。这就是为什么这让我如此困惑。
  • @Adam:好的,int? 类型的常量应该可以工作,但int 类型的常量不行。我想我现在和你在一起......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-15
  • 1970-01-01
  • 2011-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多