为什么在表达式树中需要进行转换
从这个问题我5分钟前问过,很明显,以下代码抛出异常,表示
From this question I asked 5 minutes ago, it's clear that the following code throws an exception, stating that
未处理的异常:
System.InvalidOperationException:
二进制运算符Equal未定义
'System.Nullable`1 [System.Int32]'和
'System.Int32'
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
确实工作
This code, however, with the type explicitly listed in Expression.Constant
does work
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?
The question is, why is Expression.Constant
not able to convert implicitly from int?
to ... int?
表达式树在较低级别工作到正常的源代码 - 你可以将它们认为是在层级上工作的输出,而不是输入。所以在C#中有一个从 int
到 int
的隐式转换时,必须在IL中表示转换编译器将其用于正常的方法...所以它也必须存在于表达式树表示中。
Expression trees work at a lower level to normal source code - you can think of them as working at the level of the output of the compiler rather than the input. So while there's an implicit conversion from int
to int?
in C#, that conversion has to be represented in IL whenever the compiler uses it for a normal method... so it also has to be present in an expression tree representation.
说完了,你的例子有点不清楚,因为您正在尝试使用 int
(即 ItemTypeValue.Value
)作为 int?
常量,我们不知道什么类型的 ItemType
属性是。
Having said that, your example is somewhat unclear, given that you're trying to use an int
(namely ItemTypeValue.Value
) as a value for an int?
constant, and we don't know what the type of the ItemType
property is either.
您希望工作的简短但完整的示例真的有帮助。
A short but complete example of what you'd expect to work would really help.
编辑:好的,我以为我现在和你在一起问题是如果您使用
Okay, I think I'm with you now. The problem is that if you use
int? foo = 1;
Expression.Constant(foo);
然后调用表达式(对象) 其中包含 foo
。在这一点上, Expression.Constant
不能说它原来是一个 int?
,因为它现在是一个盒装 INT
。这就是.NET Boxing的工作原理:
then that calls Expression.Constant(object)
which boxes the value of foo
. At that point, Expression.Constant
can't tell it was originally an int?
, because it's now a boxed int
. That's just the way .NET boxing works:
int? foo = 1;
object o = foo;
Console.WriteLine(o.GetType()); // Prints System.Int32
Expression.Constant
从给定的值确定表达式的总体类型,所以它创建一个 int
表达式,而你真的想要一个 int ?
表达式。
That overload of Expression.Constant
determines the overall type of the expression from the value that it's given - so it creates an int
expression, whereas you really want an int?
expression.
为了正确维护类型信息,您必须使用允许您指定类型的重载: p>
In order to maintain the type information properly, you have to use the overload which allows you to specify the type:
int? foo = 1;
Expression.Constant(foo, typeof(int?));
您的问题仍然不完全清楚哪些代码有效,哪些代码不起作用,但希望帮助...
It's still not entirely clear from your question which code works and which doesn't, but hopefully that'll help...