【问题标题】:Lambdas with captured variables带有捕获变量的 Lambda
【发布时间】:2008-12-04 01:38:46
【问题描述】:

考虑以下代码行:

private void DoThis() {
    int i = 5;
    var repo = new ReportsRepository<RptCriteriaHint>();

    // This does NOT work
    var query1 = repo.Find(x => x.CriteriaTypeID == i).ToList<RptCriteriaHint>();      

    // This DOES work
    var query1 = repo.Find(x => x.CriteriaTypeID == 5).ToList<RptCriteriaHint>();    
}

因此,当我将一个实际数字硬连接到 lambda 函数中时,它可以正常工作。当我在表达式中使用捕获的变量时,它会返回以下错误:

对象类型不存在映射 ReportBuilder.Reporter+c__DisplayClass0 到已知的托管提供商本地 输入。

为什么?我该如何解决?

【问题讨论】:

  • 我猜不是。我会牢记这一点,以备不时之需......

标签: variables c#-3.0 subsonic lambda


【解决方案1】:

从技术上讲,解决此问题的正确方法是让从 lambda 接受表达式树的框架评估 i 引用;换句话说,它是某些特定框架的 LINQ 框架限制。它目前正在尝试做的是将i 解释为从数据库中对其已知的某种类型(提供者)的成员访问。由于 lambda 变量捕获的工作方式,i 局部变量实际上是隐藏类中的一个字段,即提供者无法识别的具有有趣名称的字段。

所以,这是一个框架问题。

如果你真的必须通过,你可以手动构造表达式,如下所示:

ParameterExpression x = Expression.Parameter(typeof(RptCriteriaHint), "x");
var query = repo.Find(
    Expression.Lambda<Func<RptCriteriaHint,bool>>(
        Expression.Equal(
            Expression.MakeMemberAccess(
                x,
                typeof(RptCriteriaHint).GetProperty("CriteriaTypeID")),
            Expression.Constant(i)),
        x)).ToList();

...但这只是受虐狂。

您对此条目的评论促使我进一步解释。

Lambda 可以转换为以下两种类型之一:具有正确签名的委托,或具有正确签名的Expression&lt;TDelegate&gt;。 LINQ 到外部数据库(与任何类型的内存查询相反)使用第二种转换工作。

编译器将 lambda 表达式转换为表达式树,粗略地说,通过:

  1. 语法树由编译器解析 - 这适用于所有代码。
  2. 在考虑变量捕获后重写语法树。捕获变量就像在普通委托或 lambda 中一样 - 因此会创建显示类,并将捕获的本地变量移入其中(这与 C# 2.0 匿名委托中的变量捕获行为相同)。
  3. 新语法树被转换为对Expression 类的一系列调用,以便在运行时创建一个对象树,忠实地表示已解析的文本。

LINQ to external data sources 应该采用这个表达式树并解释它的语义内容,并将树内的符号表达式解释为引用特定于其上下文的事物(例如 DB 中的列)或立即值转换。通常,System.Reflection 用于查找特定于框架的属性来指导这种转换。

但是,SubSonic 似乎没有正确处理无法找到特定领域对应关系的符号引用;而不是评估符号引用,它只是下注。因此,这是一个亚音速问题。

【讨论】:

  • 框架是SubSonic 3.0。但是不应该在传递给 .Find 方法之前评估比较表达式吗?看看,比较表达式怎么是正则c#代码?
  • 不,比较表达式在通过之前求值。
  • 谢谢,我会联系 SubSonic 作者,看看它为什么不处理捕获的变量。
  • 我已经更新了我的帖子。实际上,我在上面手动创建的表达式树是您的工作案例发生的近似值,除了 Expression.Constant(i) 之外,编译器将生成 Expression.Constant(5)。
  • 已确认。这是 SubSonic 3 中的一个已知问题,将在下周解决。
猜你喜欢
  • 2015-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-11
  • 2013-11-26
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多