LINQ查询 – 解释为什么这些示例不同
我正在阅读“LINQ Pocket Reference”这本书,并且有一个特殊的例子(稍微修改如下),我很难理解……书中的解释有点简短,所以我想知道是否有人可以一步一步地打破它,这样才有意义……
IEnumerable query2 = "Not what you might expect"; foreach (char vowel in "aeiou") { var t = vowel; query2 = query2.Where(c => c != t); // iterate through query and output (snipped for brevity) }
输出:
不是你所期望的 不是你可能xpct 不是你的xpct Nt wht yu mght xpct Nt wht y mght xpct
这对我来说很有意义……但是,事实并非如此。
IEnumerable query2 = "Not what you might expect"; foreach (char vowel in "aeiou") { query2 = query2.Where(c => c != vowel); // iterate through query and output (snipped for brevity) }
不是你所期望的 不是你可能的xpct 不是你期望的 你可能会期待什么 不是你所期望的
哪个没…
有人可以给我一个更好的解释,确切地说这里发生了什么?
第一个例子会发生的是元音的值被捕获到局部(到for循环的范围)变量中。
然后,查询的where子句将使用捕获的变量。 像这样的where子句使用匿名方法/ lambda方法,它可以捕获局部变量。 然后会发生的是它捕获变量的当前值。
但是,在第二个类中,它不捕获当前值,只捕获要使用的变量,因此,由于此变量发生更改,因此每次执行循环时,都会在最后一个上构建一个新的Where子句,但是你有点修改所有前面的那些,因为你改变了变量。
因此,在第一个示例中,您将获得此类查询:
IEnumerable query2 = "Not what you might expect"; Char t1 = 'a'; query2 = query2.Where(c => c != t1); Char t2 = 'e'; query2 = query2.Where(c => c != t2); Char t3 = 'i'; query2 = query2.Where(c => c != t3); Char t4 = 'o'; query2 = query2.Where(c => c != t4); Char t5 = 'u'; query2 = query2.Where(c => c != t5);
在第二个例子中,你得到这个:
IEnumerable query2 = "Not what you might expect"; Char vowel = 'a'; query2 = query2.Where(c => c != vowel); vowel = 'e'; query2 = query2.Where(c => c != vowel); vowel = 'i'; query2 = query2.Where(c => c != vowel); vowel = 'o'; query2 = query2.Where(c => c != vowel); vowel = 'u'; query2 = query2.Where(c => c != vowel);
当你执行第二个例子时, vowel
的值将是’u’,所以只有u才会被删除。 但是,你在同一个字符串上有5个循环去除’u’,但只有第一个当然会这样做。
这个变量的捕获是我们在使用匿名方法/ lambdas时所遇到的事情之一,你可以在这里阅读更多相关内容: C#深度:闭包之美 。
如果您将该页面向下浏览到比较捕获策略:复杂性与功率下的文本,您将找到此行为的一些示例。
实际上,通过重读它,它是有道理的。 使用temp变量意味着在查询中捕获了temp本身…我们正在评估循环五次,因此每个查询版本都有五个实例化的临时变量引用。
在没有temp变量的情况下,只有对循环变量的引用。
所以五个引用与一个引用相比。 这就是它产生如图所示结果的原因。
在第一种情况下,一旦完全评估了循环,查询就使用了对temp变量的五个引用,因此分别剥离了a,e,i,o和u。
在第二种情况下,它正在做同样的事情……只有所有五个引用都属于同一个变量,显然只包含一个值。
故事的道德:认为“参考”而不是“价值”。
那么,这对现在的其他人有意义吗?