带有捕获变量的 Lambda 表达式
考虑以下代码行:
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 到已知的本地托管提供商 类型。
为什么? 我该如何修复它?
Consider the following line of code:
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>();
}
So when I hardwire an actual number into the lambda function, it works fine. When I use a captured variable into the expression it comes back with the following error:
No mapping exists from object type
ReportBuilder.Reporter+<>c__DisplayClass0
to a known managed provider native
type.
Why? How can I fix it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
从技术上讲,解决此问题的正确方法是让框架从 lambda 接受表达式树来评估
i
引用; 换句话说,这是某些特定框架的 LINQ 框架限制。 它当前正在尝试做的是将i
解释为对数据库中已知的某种类型(提供程序)的成员访问。 由于 lambda 变量捕获的工作方式,i
局部变量实际上是隐藏类中的一个字段,该类具有有趣的名称,但提供程序无法识别该字段。所以,这是一个框架问题。
如果你真的必须勉强度日,你可以手动构建表达式,如下所示:
...但这只是受虐狂。
您对此条目的评论促使我进一步解释。
Lambda 可转换为以下两种类型之一:具有正确签名的委托,或正确签名的
Expression
。 外部数据库的 LINQ(与任何类型的内存中查询相反)使用第二种转换。粗略地说,编译器通过以下方式将 lambda 表达式转换为表达式树:
Expression
类的一系列调用,以便在运行时创建一个忠实表示已解析文本的对象树。LINQ to 外部数据源应该采用此表达式树并解释它的语义内容,并将树内的符号表达式解释为引用特定于其上下文的事物(例如数据库中的列)或要转换的立即值。 通常,System.Reflection 用于查找特定于框架的属性来指导此转换。
然而,SubSonic 似乎没有正确处理符号引用,它无法找到特定于域的对应关系; 它不是评估象征性参考,而是只是下注。 因此,这是一个亚音速问题。
Technically, the correct way to fix this is for the framework that is accepting the expression tree from your lambda to evaluate the
i
reference; in other words, it's a LINQ framework limitation for some specific framework. What it is currently trying to do is interpret thei
as a member access on some type known to it (the provider) from the database. Because of the way lambda variable capture works, thei
local variable is actually a field on a hidden class, the one with the funny name, that the provider doesn't recognize.So, it's a framework problem.
If you really must get by, you could construct the expression manually, like this:
... but that's just masochism.
Your comment on this entry prompts me to explain further.
Lambdas are convertible into one of two types: a delegate with the correct signature, or an
Expression<TDelegate>
of the correct signature. LINQ to external databases (as opposed to any kind of in-memory query) works using the second kind of conversion.The compiler converts lambda expressions into expression trees, roughly speaking, by:
Expression
class so that, at runtime, an object tree is created that faithfully represents the parsed text.LINQ to external data sources is supposed to take this expression tree and interpret it for its semantic content, and interpret symbolic expressions inside the tree as either referring to things specific to its context (e.g. columns in the DB), or immediate values to convert. Usually, System.Reflection is used to look for framework-specific attributes to guide this conversion.
However, it looks like SubSonic is not properly treating symbolic references that it cannot find domain-specific correspondences for; rather than evaluating the symbolic references, it's just punting. Thus, it's a SubSonic problem.