2012-10-13 25 views
13

W tym fragmencie kodu:Dlaczego lambdas może konwertować wywołania funkcji na Akcje?

List<String> names = new List<String>(); 
names.Add("Bruce"); 
names.Add("Tom"); 
names.Add("Tim"); 
names.Add("Richard"); 

names.ForEach(x => Print(x)); 

private static string Print(string s) 
{ 
    Console.WriteLine(s); 
    return s; 
} 

Print nie jest Action na pewno, ponieważ wraca string; jednak czy jest to x=> Print(x)?

+3

Popraw proszę tytuł tego pytania. Google używa go do oznaczania swoich wyników wyszukiwania, a Twój tytuł nie jest w ogóle wyszukiwany w Google. –

Odpowiedz

16

Typ wyrażenia lambda x => Print(x) jest określany na podstawie jego kontekstu. Ponieważ kompilator wie, że lambda jest przypisana do Action<string>, kompilator odrzuca typ zwracany w metodzie Print(s), tak jakby był to wyrażenie o wyrażeniu .

Jest to ważne konwersja:

Action<string> myAction = y => Print(y); 

Innymi słowy, zarówno

Print("something"); 

i

int x = Print("something"); 

są poprawne zwyczaje sposobu Print; mogą być używane w lambdach w ten sam sposób.

+0

Ponieważ Print zwraca ciąg znaków, dlaczego kompilator może przyjąć typ zwrotu jako nieważny i dopasować działanie? –

+4

Ponieważ legalną rzeczą do wykonania ciągu jest wyrzucenie go. Nie musisz wyraźnie określać, że odrzucasz wartość zwracaną - nieużywanie jej jest wystarczające. –

+0

W rzeczywistości prawie za każdym razem, gdy przypisujesz zmienną, robisz to samo, ponieważ wyrażenia przypisania zwracają przypisaną wartość! A więc akcja, która przypisuje namór, działa tak samo. –

9

x => Print(x) jest lambda, który zamienił się w metodzie tutaj odpowiednik:

void MyPrintLambda(string x) { Print(x); } 

Jeśli kontekst wezwał do, powiedzmy, Func<string, string>, to byłoby to:

string MyPrintLambda(string x) { return Print(x); } 

Lub jeśli był to Func<string, object>, byłby to:

object MyPrintLambda(string x) { return Print(x); } 

Ponieważ kompilator może przekształcić x => Print(x) w Action<string> po prostu ignorując typ zwracany (tj. pierwszy przykład), może się skompilować.

+1

Ostatni bit nie jest całkiem poprawny, 'names.ForEach (Print)' nie będzie się kompilował, ponieważ 'Print' NIE jest zamienny na' Action ',' x => Print (x) 'jest jednak ponieważ typy wyrażeń są zdefiniowane na podstawie użycia – mlorbetske

+0

@klubbetske masz rację, usunąłem ten bit teraz. –

4

Z tego samego powodu, że będzie to ważne:

foreach (string name in names) 
{ 
    Print(name); 
} 

Metoda druku() zwraca wartość w tym kodzie, jak również, ale nikt nie mógł się spodziewać, że jest to błąd. Po prostu można odrzucić wartość zwrotu.

Powiązane problemy