【问题标题】:C# method group strangenessC#方法组奇怪
【发布时间】:2010-02-09 16:04:10
【问题描述】:

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

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?

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

【问题讨论】:

    标签: c# lambda method-group


    【解决方案1】:

    List&lt;T&gt;.ForEach 正在寻找Action&lt;T&gt;。当你写

    n.ForEach(Console.WriteLine);
    

    您在这里拥有的是方法组Console.WriteLine 的成员之一,扮演Action&lt;T&gt; 的角色。编译器将寻找吃掉int 实例的Console.WriteLine 的最佳重载。事实上,它会使用重载Console.WriteLine(int)。然后它将使用这个重载来扮演Action&lt;int&gt;的角色。

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

    但是,当你写的时候

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

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

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

    然后

    n.ForEach(DoSomething);
    

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

    关键是在第一种情况下Action&lt;int&gt; Console.WriteLine(int)。然而,在第二种情况下,Action&lt;int&gt; 是一个中间人(lambda 表达式),它本身将调用Console.WriteLine(int)

    【讨论】:

    • ++ 表示编译器“吃掉”了 Console.WriteLine 的重载!
    • 表达得非常好。谢谢!
    【解决方案2】:

    如果您考虑到实际发生的情况,这就不那么令人困惑了。

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

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

    【讨论】:

    • C# 2.0 有匿名委托语法 (delegate(){}),但它仍然不够甜美,而且会使 LINQ 看起来很混乱。
    猜你喜欢
    • 1970-01-01
    • 2021-01-24
    • 2017-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-26
    • 1970-01-01
    相关资源
    最近更新 更多