2010-02-09 8 views
13

Ich entdeckte etwas sehr Seltsames, das ich hoffentlich besser verstehen würde.C# Methodengruppe Fremdheit

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

, die als neu beschrieben werden kann:

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

Wie ist es möglich, den Lambda-Ausdruck Parameter (i =>) und nach wie vor die aktuelle Position Console.WriteLine bestanden haben auszulassen?

Danke für jede Einsicht. -Keith

Antwort

33

ist auf der Suche nach einem Action<T>. Wenn Sie

n.ForEach(Console.WriteLine); 

schreiben, was Sie hier haben, ist eines der Mitglieder der Methodengruppe Console.WriteLine die Rolle eines Action<T> spielen. Der Compiler sucht nach der besten Überladung von , die Instanzen von int isst. In der Tat wird es die Überlastung Console.WriteLine(int) verwenden. Es wird dann diese Überladung verwenden, um die Rolle eines Action<int> zu spielen.

Einzelheiten dazu finden Sie unter §6.6 der Spezifikation (Methodengruppenkonvertierungen).

Wenn Sie jedoch

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

schreiben wir haben eigentlich eine ganz andere Action<int> Im ersten Fall war die Action<int>Console.WriteLine(int). Hier ist die Action<int> entsprechen Sie

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

und dann

n.ForEach(DoSomething); 

geschrieben zu haben (Natürlich hat der Compiler durch die gleiche Methode Gruppenprozess gehen, wie oben beschrieben, um herauszufinden, was gemeint ist, von DoSomething).

Der Punkt ist, in dem ersten Fall, dass die Action<int>istConsole.WriteLine(int). Im zweiten Fall ist der Action<int> jedoch ein mittlerer Mann (der Lambda-Ausdruck), der selbst Console.WriteLine(int) aufrufen wird.

+1

++ für Bilder des Compilers "Essen" eine Überladung von Console.WriteLine! –

+1

Sehr schön artikuliert. Vielen Dank! – Keith

+0

Schöne Erklärung. –

2

Dies ist weniger verwirrend, wenn Sie bedenken, was wirklich passiert.

Sie übergeben eine Methode an ein Delegate-Argument. Die meiste Zeit denken wir an Delegierte im Kontext von Ereignissen, aber sie können auch Parameter für Methoden sein. Es erscheint nicht seltsam, wenn eine Methode ohne Argumente zu einem Ereignis hinzugefügt wird, es ist nur ungewöhnlich, wenn es in diesem Kontext ausgeführt wird.

Vor lambdas mussten Sie dies immer tun, und es war so ein Schmerz, dass man niemals eine Bibliothek in Betracht ziehen würde, die wie LINQ aussah. Mit Lambdas ist das einfacher, aber Sie können immer auch den alten Weg gehen.

+0

C# 2.0 hatte die anonyme Delegatensyntax ('delegate() {}'), aber es war immer noch nicht süß genug syntaktischer Zucker und würde LINQ ziemlich unordentlich aussehen lassen. – Gabe

Verwandte Themen