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

时间:2011-02-21 15:01:46

标签: c# entity-framework expression-trees

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

  

未处理的例外情况:   System.InvalidOperationException:The   二进制运算符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?

1 个答案:

答案 0 :(得分:15)

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

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