2010-04-22 18 views
24

Mam nadzieję, że poprawnie sformułowałem tytuł mojego pytania.Dlaczego nie można używać wbudowanych anonimowych obiektów lambdas lub delegatów?

w C# można używać lambdy (delegatów), lub starszej delegata składni Aby to zrobić:

Func<string> fnHello =() => "hello"; 
Console.WriteLine(fnHello()); 

Func<string> fnHello2 = delegate() 
{ 
    return "hello 2"; 
}; 
Console.WriteLine(fnHello2()); 

Więc dlaczego nie mogę „inline” lambda lub organ delegat i uniknąć przechwytywania to w nazwie zmiennej (czyniąc ją anonimową)?

// Inline anonymous lambda not allowed 
Console.WriteLine(
    (() => "hello inline lambda")() 
); 

// Inline anonymous delegate not allowed 
Console.WriteLine(
    (delegate() { return "hello inline delegate"; })() 
); 

Przykładem, który działa w JavaScript (tylko dla porównania) jest:

alert(
    (function(){ return "hello inline anonymous function from javascript"; })() 
); 

która produkuje oczekiwany powiadomienie pudełko.

UPDATE: Wydaje się może mają inline anonimowy lambda w C#, jeśli rzucisz odpowiednio, ale ilość startów() 's, aby go niesforny.

// Inline anonymous lambda with appropriate cast IS allowed 
Console.WriteLine(
    ((Func<string>)(() => "hello inline anonymous lambda"))() 
); 

Może kompilator nie można wywnioskować sig z anonimowego delegata wiedzieć, które Console.WriteLine() starasz się nazywają? Czy ktoś wie, dlaczego ta konkretna obsada jest wymagana?

+0

Rozważ to: 'public static R Eval (Func m) {return m();}'. Możesz wtedy powiedzieć 'Eval (() => {return" test ";})' który jest trochę ładniejszy, lub nawet 'Eval (() => {return" test ";})'. – Ben

Odpowiedz

19

Lambdas w języku C# nie ma typów, dopóki nie zostaną użyte w kontekście, który je rzuca na delegata lub typ wyrażenia. Dlatego nie można powiedzieć

var x =() => "some lambda"; 

Możecie cieszyć

http://blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous-methods-part-two.aspx

http://blogs.msdn.com/ericlippert/archive/2007/01/12/lambda-expressions-vs-anonymous-methods-part-three.aspx

+0

+1. Ważna podstawowa koncepcja dotycząca lambdas w języku C#. – Cheeso

2

Można użyć wbudowanych wyrażeń lambda do metod, które odbywają się w parametrze delegata.

Jest jednak niewielki haczyk - jeśli parametr zostanie wpisany jako podstawowy typ Delegata, należy jawnie rzucić go do konkretnej pochodnej Delegata (powiedzmy Działanie); inaczej kompilator narzekałby.

Podobne pytania:
Anonymous method in Invoke call
Anonymous methods and delegates

8

Kiedy piszesz Func<string> = ..., kompilator wie, że musi utworzyć obiekt typu Func<string>. Ale kiedy piszesz ten delegat w linii, kompilator nie zna obiektu, który typ musi utworzyć.

Powiedziawszy wyżej, można wyciągnąć oczywisty wniosek: po prostu dokładnie powiedz kompilatorowi typ!

Console.WriteLine(new Func<string>(() => "Hello")()); 

UPDATE

Ok, podczas gdy pisałem odpowiedź, aktualizowania swojego posta. Wierzę, że moja odpowiedź powyżej już odpowiada na pytanie "dlaczego ten konkretny typ jest wymagany". Powtarzam: ponieważ kompilator nie zna obiektu, który typ utworzyć.

Teraz, aby opracować nieco na ", kompilator nie może wywnioskować sig z anonimowego delegata" część. Widzisz, to nie jest tak jak w JavaScript. W języku C# nie ma typowego "funkcji" (lub "metody"). Każdy delegat musi mieć jawnie określoną nazwę podpisu i typu. A kiedy tworzysz delegata, kompilator musi wiedzieć, jakiego typu.

Teraz mogę zobaczyć, jak możesz sugerować, że kompilator może po prostu skonstruować typ delegata w locie, tak jak robi to z anonimowymi typami obiektów (aka new { a = 1, b = "xyz" }). Ale pomyślcie o tym przez chwilę: i tak nie byłoby zapewne takiego delegata. Mam na myśli, że nie możesz przekazać go innej metodzie, ponieważ ta metoda musi najpierw zadeklarować typy jej argumentów. I możesz wydobyć z niego wydarzenie, ponieważ znowu musisz mieć nazwany typ.

Coś takiego ...

11

wydaje się działać, jeśli dasz mu obsady typ:

String s = ((Func<String>) (() => "hello inline lambda"))(); 

Czy to bezużyteczne? Nie do końca. Weź poniżej:

String s; 
{ 
    Object o = MightBeNull(); 
    s = o == null ? "Default value" : o.ToString(); 
} 

Teraz pomyśl o tym:

String S = ((Func<Object,String>)(o => o == null ? "Default value" : o.ToString()) 
    )(MightBeNull()); 

To trochę brzydki, ale jest zwarta.