C # метод группы странность - PullRequest
       54

C # метод группы странность

13 голосов
/ 09 февраля 2010

Я обнаружил нечто очень странное, что надеюсь лучше понять.

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));

Как можно пропустить параметр лямбда-выражения (i =>) и по-прежнему передавать текущий элемент в console.WriteLine?

Спасибо за понимание. -Keith

Ответы [ 2 ]

33 голосов
/ 09 февраля 2010

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> - это средний человек (лямбда-выражение), который сам по себе назовет Console.WriteLine(int).

2 голосов
/ 30 января 2011

Это менее запутанно, если учесть, что на самом деле происходит.

Вы передаете метод аргументу делегата. Большую часть времени мы думаем о делегатах в контексте событий, но они также могут быть параметрами для методов. Это не кажется странным, когда метод добавляется к событию без аргументов, это просто необычно, когда выполняется в этом контексте.

До лямбды вам приходилось делать это все время, и это было такой болью, что никто бы не подумал об использовании библиотеки, похожей на LINQ. С Lambdas это сделать проще, но вы всегда можете сделать это и по-старому.

...