【发布时间】:2017-05-21 07:11:50
【问题描述】:
这个问题与闭包的工作原理无关。这个问题是关于 LINQ 如何决定在运行时可解析表达式中引用什么,以及评估什么并将其放入该表达式。
这个问题试图了解 LINQ 的工作原理,以另一种语言实现类似的东西。
考虑以下要转换为表达式树的 LINQ 查询:
var my_variable = "abc";
var qry = from x in source.Foo
where x.SomeProp == my_variable
select x.Bar;
由编译器映射成代码:
var qry = source.Foo
.Where(x => x.SomeProp == my_variable)
.Select(x => x.Bar);
当它被转换为表达式树时,LINQ 如何知道将哪个引用到表达式中,以及评估哪个并将结果放入表达式中?
例如,它如何知道评估 my_variable 并将结果放入 expressino,但将 x.SomeProp 和 == 转换为 LINQ 表达式树的一部分?
C# 编译器是否有一个硬编码的特殊列表,其中列出了为 LINQ 引用的表达式? (即可以翻译成SQL的最外层操作,包括:==、!=、&&、||、、=、子字符串等)
【问题讨论】:
-
这不是关于闭包如何捕获变量的问题,而是关于 LINQ 如何知道要捕获哪些表达式以及将哪些表达式编码为表达式的问题。
-
LINQ 永远不会关闭任何东西。您只是将 lambdas 传递给 LINQ 调用,而正是那些 与 LINQ 毫无关系的 lambdas 创建了闭包。如果你想知道 lambdas 是如何创建闭包的,你有副本。如果您不这样做,那么您的问题就没有任何问题。说你的问题不是重复的当你问的问题与重复的完全相同是没有意义的。
-
也许我对“捕获”一词的使用令人困惑...... LINQ 实现能够看到未计算的表达式(如 +)以及局部变量和函数调用的结果。这就是我要问的。
-
没有个表达式在创建表达式时会被计算,并且所有可以在任何时候被计算表达式的任何消费者。这also 与LINQ 无关。 lambda 将拥有关于代码是什么的所有信息,并且实际的查询提供者可以(如果它选择)将部分或全部表达式评估为他们认为合适的值。 LINQ 只接受表达式并将它们提供给查询提供程序。
-
我明白了我的困惑以及为什么这与 LINQ 无关,而仅与表达式树有关。我在想表达式树只是一个 AST(lambda 文本的结构化表示),但它们还包含对实时程序对象的引用。对于出现在 lambda 中的捕获变量,表达式树包含一个 MemberExpression/ConstantExpression 对,它可以访问变量的框。