2012-01-04 48 views
15

我在理解表达式和函数的工作方式之间的差异时遇到了一些困难。 这个问题打开了,当有人从改变方法签名:关于传递表达式与函数参数的困惑

public static List<Thing> ThingList(Func<Thing, bool> aWhere) 

public static List<Thing> ThingList(Expression<Func<Thing, bool>> aWhere) 

这打破了我的调用代码。旧的调用代码(合作)是这样的:

 ... 
     object y = new object(); 
     Func<Thing, bool> whereFunc = (p) => p == y; 
     things = ThingManager.ThingList(whereFunc); 

新的代码(不工作)看起来是这样的:

 ... 
     object x = new object(); 
     Expression<Func<Thing, bool>> whereExpr = (p) => p == x; 
     things = ThingManager.ThingList(whereExpr); 

这里面失败ThingList(...)上

 var query = (from t in context.Things.Where(aWhere) 
     ... 

随着运行时错误::利用表达式线

Unable to create a constant value of type 'System.Object'. Only primitive types ('such as Int32, String, and Guid') are supported in this context. 

这个例子很有意思,但我的猜测是它与本地对象变量x没有正确“复制”到表达式中有关。

有人可以解释一般如何处理这种情况,为什么Func工作,但Expression没有?

回答

11

的原因变化几乎可以肯定是“推”的谓词的评价到底层存储,它备份你的context。除了将所有Things带入内存,然后使用Func<Thing,bool>来决定保留哪些内容,更改的API的作者决定使用IQueryable,并且需要Expression<Func<Thing,bool>>

你在错误的起源上是正确的:与内存中的谓词不同,IQueryable不能使用它不知道的对象,例如: object的任意实例。

您需要做的是更改表达式以避免引用目标数据存储不支持的数据类型对象(我假设该表达式最终进入实体框架或Linq2Sql上下文)。例如,而不是说

object x = new object(); 
Expression<Func<Thing, bool>> whereExpr = (p) => p == x; 
things = ThingManager.ThingList(whereExpr); 

你应该说

Thing x = new Thing {id = 123}; 
Expression<Func<Thing, bool>> whereExpr = (p) => p.id == x.id; 
things = ThingManager.ThingList(whereExpr); 

(你的后备存储几乎可以肯定明白整数)

+0

是,它使得它的方式到实体框架。我想我必须做两个方法,一个用于Expression,另一个用于Func在必要时使用。 – Erix 2012-01-04 14:32:08

6

表达和Func键之间的差别在这里的答案是更好的描述:Difference between Expression<Func<>> and Func<>

一个快速的解决方法,使再次这项工作将是编译表达式返回到函数求。

var query = (from t in context.Things.Where(aWhere.Compile())