对传递 Expression 与 Func 参数感到困惑
我在理解表达式和函数工作方式之间的差异时遇到一些困难。 当有人将方法签名从以下位置更改
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
却不行?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
几乎可以肯定,更改的原因是将谓词的计算“推送”到底层存储中,该存储支持您的
上下文
。更改后的 API 的作者决定使用 IQueryable,而不是将所有Things
放入内存,然后使用Func
来决定保留哪些内容。 ,并且需要一个Expression>
来实现。您对错误的起源是正确的:与内存谓词不同,
IQueryable
不能使用它不知道的对象,例如object
的任意实例。您需要做的是更改表达式,以避免引用目标数据存储不支持的数据类型的对象(我假设该表达式最终会进入实体框架或 Linq2Sql 上下文)。例如,
您应该说
(您的后备存储几乎肯定可以理解整数),而不是说
The reason for the change almost certainly was to "push" the evaluation of your predicate into the underlying store, which backs your
context
. Instead of bringing allThings
into memory and then usingFunc<Thing,bool>
to decide which ones to keep, the author of the changed API decided to useIQueryable
, and needed anExpression<Func<Thing,bool>>
for that.You are correct on the origin of the error: unlike in-memory predicates,
IQueryable
cannot use objects that it does not know, e.g. arbitrary instances ofobject
.What you need to do is to change the expression to avoid referencing objects of data types not supported by your target data store (I assume the expression eventually makes its way into either an Entity Framework or a Linq2Sql context). For example, instead of saying
you should say
(your backing store almost certainly understands integers)
表达式和 Func 之间的区别在此处的答案中得到了更好的描述:表达式与 Func 之间的区别>和 Func<>
使此功能再次工作的快速解决方法是将表达式编译回 Func。
The difference between Expression and Func is better described in the answers here: Difference between Expression<Func<>> and Func<>
A quick workaround to make this work again would be to compile the expression back into a Func.