LINQ中的嵌套'froms'

Kon*_*dov 10 c# linq

我是LINQ的新手,我遇到嵌套的问题:

using System;
using System.Linq;
class MultipleFroms
{
    static void Main()
    {
        char[] chrs = { 'A', 'B', 'C'};
        char[] chrs2 = { 'X', 'Y', 'Z' };
        var pairs = from ch1 in chrs
                    from ch2 in chrs2
                    select ch1+" "+ ch2;
        Console.WriteLine("For ABC and XYZ: ");
        foreach (var p in pairs)
            Console.WriteLine(p);
        Console.WriteLine();

        Console.WriteLine("For D and W: ");
        chrs = new char[] { 'D' };
        chrs2 = new char[] { 'W' };
        foreach (var p in pairs)
            Console.WriteLine(p);
    }
}
Run Code Online (Sandbox Code Playgroud)

在输出中我有:

For ABC and XYZ:
A X
A Y
A Z
B X
B Y
B Z
C X
C Y
C Z

For D and W:
A W
B W
C W
Run Code Online (Sandbox Code Playgroud)

但我预计:

...
For D and W:
D W
Run Code Online (Sandbox Code Playgroud)

为什么pairs在第二种情况下使用"旧" chrs,{ 'A', 'B', 'C'}而不是{'D'}

Min*_*s97 13

这个问题有几个很好的答案,说明显而易见的 - 你需要重新分配你的pairs变量.但是,我对这种奇怪的行为更感兴趣 - 因为,为什么重新分配chrs2会对枚举的结果产生影响,而重新分配chrs则不会.

如果我们使用嵌套from-s,看起来像重新分配任何已使用的集合(FIRST除外)会影响枚举的结果:http://ideone.com/X7f3eQ.

现在,正如您应该知道的那样,LINQ"查询语法"只是用于链接来自System.Linq库的扩展方法调用的语法糖.让我们来看看你的具体例子:

var pairs = from ch1 in chrs
            from ch2 in chrs2
            select ch1 + " "+ ch2;
Run Code Online (Sandbox Code Playgroud)

var pairs = chrs.SelectMany(ch1 => chrs2, (ch1, ch2) => ch1 + " " + ch2);
Run Code Online (Sandbox Code Playgroud)

(或者,使用非扩展方法语法SelectMany(chrs, ch1 => chrs2, (ch1, ch2) => ch1 + " " + ch2))

(请在此处查看:http://ideone.com/NjVeLD)

发生什么了?SelectManychrs两个lambda作为参数,并生成一个IEnumerable,然后可以枚举它们以开始实际评估.

现在,每当我们重新分配时chrs2,它都会在lambda中发生变化,因为它是一个捕获的变量.但是,这显然不适用chrs!


oct*_*ccl 0

您必须将查询视为方法调用,其中该方法接收第一个数据源 ( chrs) 作为参数。问题是您无法在设置后重新分配已调用该方法的对象。第二个数据源(chrs2)就像一个全局变量,这样当你更新它的值时,查询的结果也会改变。

更好的方法是将查询转移到方法中:

public static IEnumerable<string> Pairs(char[] chrs,char[] chrs2)
{
      return from ch1 in chrs
             from ch2 in chrs2
             select ch1+" "+ ch2;
}
Run Code Online (Sandbox Code Playgroud)

这样你就可以做这样的事情:

 static void Main(string[] args)
 {
        char[] chrs = { 'A', 'B', 'C' };
        char[] chrs2 = { 'X', 'Y', 'Z' };

        Console.WriteLine("For ABC and XYZ: ");
        foreach (var p in Pairs(chrs,chrs2))
            Console.WriteLine(p);
        Console.WriteLine();

        Console.WriteLine("For D and W: ");
        chrs = new char[] { 'D' };
        chrs2 = new char[] { 'W' };
        foreach (var p in Pairs(chrs, chrs2))
            Console.WriteLine(p);
}
Run Code Online (Sandbox Code Playgroud)

  • 拜托,我想知道为什么有人投反对票。如果有人发现我有问题,请分享以改进我的答案 (2认同)