Ответ 1
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)
.