LINQ查询 - 解释为什么这些示例不同

时间:2008-12-23 19:01:46

标签: c# linq scope

我正在阅读“LINQ Pocket Reference”这本书,并且有一个特殊的例子(下面稍作修改),我很难理解...... 书中的解释有点简短,所以我想知道是否有人可以一步一步地为我分解它,这样才有意义......

    IEnumerable<char> 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)
    }

输出:

    Not wht you might expect
    Not wht you might xpct
    Not wht you mght xpct
    Nt wht yu mght xpct
    Nt wht y mght xpct

这对我来说非常有意义......但是,事实并非如此。

    IEnumerable<char> 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)
    }
    Not wht you might expect
    Not what you might xpct
    Not what you mght expect
    Nt what yu might expect
    Not what yo might expect

哪个不...

有人可以更好地解释一下这里发生了什么吗?

2 个答案:

答案 0 :(得分:10)

第一个例子的结果是元音的值被捕获到局部(到for循环的范围)变量。

然后查询的where子句将使用捕获的变量。像这样的where子句使用匿名方法/ lambda方法,它可以捕获局部变量。然后会发生的是它捕获变量的当前值。

但是,在第二个类中,它不捕获当前值,只捕获要使用的变量,因此,由于此变量发生更改,因此每次执行循环时,都会在此基础上构建新的Where子句。最后一个,但是你有点修改所有前面的那个,因为你改变了变量。

因此,在第一个示例中,您将获得此类查询:

IEnumerable<char> 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<char> 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# In Depth: The Beauty of Closures

如果您将该页面浏览到比较捕获策略:复杂性与功效下的文本,您会发现此行为的一些示例。

答案 1 :(得分:1)

实际上,通过重读它,它是有道理的。 使用temp变量意味着在查询中捕获了temp本身......我们正在评估循环五次,因此每个查询版本都有五个实例化的临时变量引用。

在没有temp变量的情况下,只有对循环变量的引用。

所以五个参考与一个参考。这就是它产生结果的原因。

在第一种情况下,一旦完全评估了循环,查询就使用了对temp变量的五个引用,因此分别剥离了a,e,i,o和u。

在第二种情况下,它正在做同样的事情......只有所有五个引用都属于同一个变量,显然只包含一个值。

故事的道德:认为“参考”而非“价值”。

那么,这对现在的其他人有意义吗?