2012-09-01 83 views
3

下面的第二個測試方法不能編譯(不能將lambda表達式轉換爲目標類型D1)。這是否意味着(非泛型)委託逆轉不適用於lambda表達式?C#委託與lambda表達式的轉換

[TestFixture] 
public class MyVarianceTests 
{ 
    private abstract class Animal {} 
    private class Tiger : Animal {} 

    private delegate Type D1(Tiger tiger); 

    private static Type M1(Animal animal) 
    { 
     return animal.GetType(); 
    } 

    [Test] 
    public void ContravariantDelegateWithMethod() 
    { 
     D1 func = M1; 
     Type result = func(new Tiger()); 
     Assert.AreEqual(result, typeof (Tiger)); 
    } 

    [Test] 
    public void ContravariantDelegateWithLambda() 
    { 
     D1 func = (Animal animal) => animal.GetType(); 
     Type result = func(new Tiger()); 
     Assert.AreEqual(result, typeof (Tiger)); 
    } 
} 

回答

5

您已經確定了語言中的不一致性。

這在language specification明確地調出:

7.15.1匿名函數簽名

[...]相比於方法組轉換(6.6節),禁忌方差不支持匿名功能 參數類型。 [...]

...這提出了一個問題:

爲什麼沒有語言的設計者費心支持這個功能嗎?

<speculation>

顯然,該功能有一些小的好處。但是它是否證明符合編譯器實現所需的額外複雜性的成本?

當你寫一個lambda表達式時,你必須已經已知確切地知道它正在轉換到哪個委託/表達式樹類型(沒有可以「保存」任意lambda表達式的通用類型)。從C#5開始,lambda(與方法相反)除了幫助創建代理/表達式樹實例之外絕對沒有其他用途。因此,顯式地沒有任何優勢(除了方便之外)指定比參數所需的更通用的類型,並期望來自編譯器的對比差異支持。您可以完全省略類型,並依賴於類型推理(或者,最壞的情況下,明確指定所需的確切參數類型),而不會在可重用性或可表達性方面造成任何損失。

這顯然不適用於除創建委託/表達式樹之外的其他用途的方法。您可能需要一個特定的功能簽名(與委託人不同),因爲它是最合適的,或者它需要它,因爲它必須滿足一個接口合同。更進一步,當您執行方法組轉換時,請考慮您(作爲創建委託/表達式樹的程序員)不一定「擁有」有問題的方法(它可能在第三方程序集中)。 lambda表達式從來就不是這種情況。

似乎語言設計者認爲實現lambda表達式的參數類型的反差並不能證明成本,與方法組不同。

</speculation>

+1

謝謝,這是我正在尋找的參考。而你對於爲什麼存在不一致的猜測對我來說也是有意義的。 – mtraudt

2

D1除了一個類型爲Tiger的參數,但您正在傳遞一種動物類型。 動物不是老虎 但老虎是動物

+0

動物是不太具體,所以分配函數,它接受一個'Animal'向被指定'Tiger'不應該是一個問題的委託。 'M1'不如'D1'具體。 – BAF

+0

+1。是啊。合作和逆變通常令人難以置信,並且不會像你第一次直覺地想到的那樣工作。 –

+0

你的回答如何不適用於方法組轉換'D1 func = M1;'? – Ani

相關問題