2012-12-20 30 views
2

通過剛剛通報了一本書(主要的),有一兩件事引起了我的眼睛 - lambda表達式定義:Lambda表達式定義(迂腐)?

lambda表達式是寫在地方 委託實例的未命名方法。

代替委託實例???

一個代表實例是對象引用到/封裝目標方法/秒:

在下面的示例的右側(其中λ表達式將是)不是委託實例。這是一種方法。

TransformerDelegate t = SquareMethod;

所以定義應已被校正到/提及:

lambda表達式是寫入到位的方法的無名方法 由代表變量引用(!)。

TransformerDelegate sqr = x => x * x; 
          ^
           | 
       ---------------+ 
       | 

      this is the location for method/anonymous methods. 

你明白我的意思?我對嗎?

p.s.我瞭解MSDN的一個:(而是想看看這本書犯了一個錯誤)

lambda表達式是可以包含 表達式和語句的匿名功能,可用於創建代表或 表達式樹類型。

+1

你對這種微妙的問題有着敏銳的眼光;你說的這句話是不正確的,也是不準確的,即使它得到了正確的想法。如果你仔細閱讀技術書籍,你很快就會發現許多這類問題。例如,即使有經驗的作者也會將「對象」與「變量」混淆起來。我編輯的唯一一本正確使用技術術語的書幾乎每次都是深度_C#。 :-) –

+0

@EricLippert謝謝埃裏克:-) –

+0

Pedantry:在聲明'TransformerDelegate t = SquareMethod;',SquareMethod不是一個方法,它是一個*方法組*。 – phoog

回答

4

lambda表達式的值是委託實例。

所以書中所指的可能是這樣的代碼:

MySquareDelegate f1 = x => x * x; 
MySquareDelegate f2 = new MySquareDelegate(MySquareMethod); 
MySquareDelegate f3 = MySquareMethod; // just shorthand for the previous line 

這是棘手的問題在1兩句話來解釋,你自己的版本

lambda表達式是無名的方法寫在地方的方法(!)被委託變量引用。

正在談論「一種方法而不是一種方法」,原來關於「方法而不是委託實例」的方法被隱式轉換爲委託實例。至少兩者似乎都不完整。

拉姆達的定義還應該包括它是一個內聯方法。

+0

+1是有意義的。在我的腦海裏,它是'MySquareDelegate f2 = MySquareMethod',在右邊只是一個方法。但老式的方式(使用新的())澄清了事情。謝謝 。所以這本書沒有錯。 –

0

基本上,代表只是一個知道如何調用特定方法的對象。因此,代理實例字面上充當調用方的委託:調用方調用委託,然後委託調用目標方法。

+0

「這個對象是由編譯器構建的」,在更精細的點上有一些光澤,不是嗎?該對象在運行時構建,而不是編譯時。 – phoog

1

其他答案錯過了lambda表達式不一定代表方法的事實。有時候,他們代表表達式樹。

根據上下文,編譯器將lambda表達式隱式轉換爲一種類型的對象或另一種類型的對象。

要指定方法,您需要指定參數和主體。在lambda表達式中,這些用=>分開。實例:

()  => 4;    //empty parameter list 
    x  => x.ToString(); //one parameter 
    (a, b) => a.Equals(b);  //two parameters 
// ^^^^^^ ^^^^^^^^^^^^ 
// |     | 
// parameter list  body 

這些lambda表達式可以分別轉化爲Func<int>Func<object, string>,和Func<object, object, bool>。也可以分別轉換爲Expression<Func<int>>,Expression<Func<object, string>>Expression<Func<object, object, bool>>

匿名方法:

delegate (object p, object q) { return string.Concat(p, q); } 
//  ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
//  parameter list  body 

下面是拉姆達轉換的兩個例子:

Func<object, object, bool> aDelegate = (o1, o2) => object.Equals(o1, o2); 
Expression<Func<object, object, bool>> anExpressionTree = (o1, o2) => object.Equals(o1, o2); 

在方法組轉換,參數和方法主體被重載解析指定。爲了簡化一下,編譯器查看具有指定名稱的方法,並根據上下文選擇正確的過載。例如,考慮SquareMethod的這些重載:

int SquareMethod(int a) { return a * a; } 
double SquareMethod(double a) { return a * a; } 

這些陳述涉及方法組轉換和重載決議:

Func<int, int> squareAnInt = SquareMethod; 
Func<double, double> squareADouble = SquareMethod; 

最後,lambda表達式不能轉換爲表達式目錄樹:

Action<object> anAction = o => { Console.WriteLine(o); }; 
Func<object, int> aFunc = o => 
    { 
     var s = (o ?? "").ToString(); 
     Console.WriteLine(s); 
     return s.Length; 
    }; 

C#語言規範(有點令人困惑)使用術語「匿名函數」來涵蓋lambda表達式和匿名方法。匿名函數可以隱式轉換爲兼容的委託類型,方法組也可以。因此,如果我們有一個稱爲DelegateType委託類型,並且像這樣的聲明/分配:

DelegateType d = [something]; 

然後[something]可以是方法基或匿名函數。換句話說,它可以是方法組,匿名方法或lambda表達式。

所以,你糾正書中的文字將是更好地說:「在地方的方法組」,但我要說的

lambda表達式是一個未命名的方法,如命名的方法組,可以用來創建委託實例。

我也想補充

在某些情況下,lambda表達式可以用來創建一個表達式樹,而不是委託實例。