13

我发现了一些非常奇怪的东西,我希望能更好地理解。

var all = new List<int[]>{
                new int[]{1,2,3},
                new int[]{4,5,6},
                new int[]{7,8,9}
              };

all.ForEach(n => n.ForEach(i => Console.WriteLine(i)));

可以重写为:

...
all.ForEach(n => n.ForEach(Console.WriteLine));

怎么可能省略 lambda 表达式参数 (i=>) 并且仍然将当前项目传递给 console.WriteLine?

感谢您的任何见解。-基思

4

2 回答 2

33

List<T>.ForEach正在寻找一个Action<T>. 当你写

n.ForEach(Console.WriteLine);

您在这里拥有的是方法组的成员之一,Console.WriteLine扮演Action<T>. 编译器将寻找Console.WriteLine吃掉int. 实际上,它会使用重载Console.WriteLine(int)。然后它将使用此重载来扮演Action<int>.

有关如何完成此操作的详细信息,请参阅规范的第 6.6 节(方法组转换)。

然而,当你写

n.ForEach(i => Console.WriteLine(i));

我们实际上有一个非常不同Action<int>的第一种情况,即Action<int>Console.WriteLine(int)。在这里,Action<int>相当于你写了

public static void DoSomething(int i) {
    Console.WriteLine(i);
}

接着

n.ForEach(DoSomething);

(当然,编译器必须经过与上述相同的方法组过程才能弄清楚 的含义DoSomething)。

关键是在第一种情况下Action<int> Console.WriteLine(int)。但是,在第二种情况下, theAction<int>是一个中间人(lambda 表达式),它本身将调用Console.WriteLine(int).

于 2010-02-09T16:07:52.407 回答
2

如果您考虑真正发生的事情,这就不那么令人困惑了。

您正在将方法传递给委托参数。大多数时候,我们在事件的上下文中考虑委托,但它们也可以是方法的参数。将方法添加到没有参数的事件中似乎并不奇怪,只是在这种情况下执行时看起来很不寻常。

在 lambdas 之前,您必须一直这样做,这太痛苦了,以至于人们永远不会考虑使用看起来像 LINQ 的库。使用 Lambdas,这更容易做到,但您也可以始终使用旧方法。

于 2011-01-30T05:43:28.047 回答