这个问题与闭包的工作方式无关。这个问题是关于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的最外层操作,包括:==,!=,&&,||,<,>,< =,> =,substring等)
答案 0 :(得分:0)
只是通过检查明确表示.SomeProp依赖于x而x在表达式树解析时不是确定性的,因为它是先前函数的输出(其中)。
my_variable不是表达式树中任何表达式的输出,因此它的值可能在表达式树解析时已知,但很可能不会在表达式树中解析。即使它是已知的,因为这会阻止编译的表达式树被重用,因此它只会被视为表达式树评估中的输入值。
我没有反编译linq,但您可以考虑以下表达式树;
ExpressionTree myEx = new ExpressionTree(
new MultiplicationExpression(
new InputVariableExpression("@MyInputVar"),
new ConstantExpression(22)
)
);
评估你可以打电话
Dictionary<string, object> inputVars = new Dictionary<string, object>();
inputVars.Add("@MyInputVar",16);
int result = myEx.Evaluate(inputVars);
解析器可能会选择烘焙常量表达式,因为它知道&#39;它不能改变,但要考虑以下几点;
ExpressionTree anotherEx = new ExpressionTree(
new AdditionExpression(
myEx,
new InputVariableExpression("@MyNextInputVar")
)
);
这在概念上类似于在Linq x =>
中使用替换变量,其中myEx是存储的表达式树,但实际上不是表达式的结果。在执行时间之前,表达式解析器无法独立地知道myEx的值。
Dictionary<string, object> inputVars = new Dictionary<string, object>();
inputVars.Add("@MyInputVar",16);
inputVars.Add("@MyNextInputVar",45);
int result = anotherEx.Evaluate(inputVars);
因此,在评估myEx
期间,此执行代码将固有地评估anotherEx
。如果myEx
中只包含ConstantExpression
元素,则可能只会对其进行一次评估并缓存结果,但由于它包含范围超出范围InputVariableExpression
,因此清除了一个评估结果不能缓存以供后续使用。
答案 1 :(得分:-1)
这很容易测试:
int i = 1;
Func<int> func = () => i;
i = 2;
Console.WriteLine(func.Invoke());
打印出2
,它告诉我们它存储符号,并且在评估函数之前不会对其进行评估。