C#方法组怪异

时间:2010-02-09 16:04:10

标签: c# lambda method-group

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

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 =&gt;)并且仍然将当前项传递给console.WriteLine?

感谢您的任何见解。 -Keith

2 个答案:

答案 0 :(得分: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)。但是,在第二种情况下,Action<int>是一个中间人(lambda表达式),它本身将调用Console.WriteLine(int)

答案 1 :(得分:2)

如果考虑到实际发生的事情,这就不那么容易混淆了。

您正在将方法传递给委托参数。大多数情况下,我们在事件的上下文中考虑代理,但它们也可以作为方法的参数。将方法添加到没有参数的事件时似乎并不奇怪,在此上下文中执行时只是异常。

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