2015-01-06 14 views
24

czytałem, że C# lambdas można imlicitly konwertowane do Akcji lub Func, ale lambda nie mogą być wykonywane bezpośrednio Define a lambda function and execute it immediately Na przykład:Jaki jest faktyczny typ lambda w C#?

int n = (()=>5)(); //doesn't work 
int n = ((Func<int>)(()=>5))(); //works 

Więc jaki jest rzeczywisty typ lambda i dlatego nie mogą być bezpośrednio nazywa? Czy to dlatego, że system typu C# jest "słabszy" niż system Haskella czy Scala?

+2

Anonimowy typ ??. –

+2

Odpowiedź w połączonym pytaniu jest ważna dla Twojego pytania. Kompilator języka C# musi znać kontekst, który jest albo przydziałem albo rzutowaniem. W pierwszej próbce nie robisz ani – Leri

+0

System typu nie jest z tym związany. 'Dim n = Function() 5' działa dobrze w VB.NET i jest podobny w F # i ma ten sam bazowy system typów. To tylko problem z C#. –

Odpowiedz

26

Wyrażenie lambda nie ma typu. Nie może, ponieważ dowolny typ w świecie .NET, który mógłby mieć, mógłby również zakodować kod typu lambda i wynik. Teraz rozważ:

x => x + 1 

Jaki typ może mieć x? Jaki będzie wynik? Nie ma jednej odpowiedzi, a wyrażenie lambda może zostać przekonwertowane na Func<int, int>, Func<double, double> i wiele innych typów delegatów o różnych parametrach. Podanie wyrażenia lambda typu uniemożliwiłoby takie wyrażenia. C# chciał zezwolić na takie wyrażenia, więc został zaprojektowany, aby nie dawać takich wyrażeń.

+1

dobrze wyjaśnione, jeśli podano przykład kodu, jestem instertsted –

+2

Nie jestem pewien jaki rodzaj przykładowego kodu masz na myśli, wszystko co mogę dodać, to przykłady typów delegatów, do których można skonwertować wyrażenie, które teraz uwzględniłem w odpowiedzi. – hvd

+0

Ma to sens. Właśnie przetestowałem to w F # i Haskell. W F # w działa tylko dla "int" - powód jest taki, że F # nie używa niejawnych konwersji. W przypadku C# - kompilator naprawdę nie może "poznać" typu, więc masz rację. –

9

To dlatego, że () => 5 może być kompatybilny z różnymi typami delegatów (np. Możesz mieć niestandardową delegate, która nie bierze nic i zwraca int). Aby utworzyć delegate, kompilator musi znać dokładny typ. Nie można wybrać losowego typu, który odpowiada Twoim potrzebom. Dlatego też, chyba że użyjesz go do rzeczywistego typu delegata, nie możesz tego zrobić.

W takich przypadkach, gdy metoda oczekuje delegate, że konwersja jest domyślnie wykonywane przez kompilator:

void Foo(Func<int> func) { } 

Foo(() => 5); 

I to jest również ważne, aby wiedzieć, że delegates są rzeczywiście klasy za kulisami. I za każdym razem, gdy tworzysz instancję delegate, kompilator tworzy instancję tego class. Więc tak czy inaczej musisz określić typ, aby kompilator wiedział, jakiego typu użyć.

+0

kiedy umieszczamy ''() => '' w '' Wybierz() '' lub '' Gdzie() '' co to znaczy? proszę wyjaśnić –

+0

@ EhsanSajjad Właśnie dodałem, że do odpowiedzi :) –

+0

Potrzebuję wyjaśnienia dla siebie, bo nie jestem jasne .. :) –