【问题标题】:Confused about passing Expression vs. Func arguments对传递 Expression 与 Func 参数感到困惑
【发布时间】:2012-01-04 14:20:42
【问题描述】:

我在理解表达式和函数的工作方式之间的差异时遇到了一些麻烦。 当有人从以下位置更改方法签名时出现此问题:

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 无效?

【问题讨论】:

    标签: c# linq linq-to-entities


    【解决方案1】:

    更改的原因几乎可以肯定是将谓词的评估“推”到底层存储中,该存储支持您的context。更改后的 API 的作者决定使用IQueryable,并为此需要一个Expression&lt;Func&lt;Thing,bool&gt;&gt;,而不是将所有Things 放入内存然后使用Func&lt;Thing,bool&gt; 来决定保留哪些。

    您对错误的起源是正确的:与内存中的谓词不同,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);
    

    (您的后备存储几乎可以肯定理解整数)

    【讨论】:

    • 是的,它进入了实体框架。我想我必须创建两种方法,一种用于 Expression,另一种用于 Func,以便在必要时使用。
    【解决方案2】:

    Expression 和 Func 之间的区别在这里的答案中有更好的描述:Difference between Expression<Func<>> and Func<>

    让这项工作再次发挥作用的快速解决方法是将表达式编译回 Func。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-19
      • 2015-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-06
      相关资源
      最近更新 更多