2011-07-15 37 views
6

可能重複:同時支持協變和逆變單個類型參數

interface ICovariant<out R> 

Covariance and Contravariance on the same type argument

您可以通過使用out關鍵字聲明泛型類型參數的協變

你可以聲明一個泛型類型參數爲contravaria NT使用in關鍵字:

interface IContravariant<in R> 

而且你還可以同時支持對不同類型的參數:

interface IVariant<out R, in A> 

那麼,爲什麼你不能詢問服務既爲單一類型的參數?

+2

詹姆斯,你今天似乎對變化感興趣。您可能想查看我的大量關於我們如何設計該功能的文章和視頻。他們在這裏:http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/default.aspx,從底部開始。 –

回答

7

那麼,爲什麼你不能支持單一類型參數?

請記住,一個接口只能在一個類型參數協變,如果該類型參數是輸出安全和接口只能在一個類型參數,如果該類型參數輸入安全進行逆變。

語法out T表示T是一個協變類型參數。

語法in TT是一個逆變類型參數。

由於T是一個協變類型參數,它根據定義輸入不安全。

由於T是一個逆變類型參數,它根據定義輸出不安全。因此,T是輸入不安全和輸出不安全。

因此,在輸入位置禁止使用T,在輸出位置禁止使用T

因此,T不能出現在輸入位置,也不能出現在接口指定的任何方法的任何輸出位置。

因此,T根本不能在接口上使用,並且作爲類型參數沒有意義。因此,語言的設計者禁止您甚至包括標記爲兩個協變和逆變的界面上,以避免醜陋

interface IFoo<in and out T> { } 
Foo<T> : IFoo<T> { } 

再這麼窩囊類型:

IFoo<Cat> cat = (IFoo<Animal>)new Foo<Dog>(); 

(如果你需要閱讀注意輸入安全和輸出安全,見語言規範13.1.3.1)

+0

哇是一個很難回答:) – JonH

+0

@JonH:謝謝,我再次嘗試。讓我知道你的想法? – jason

+0

@Jason +1好回答 – JonH

3

這是行不通的。考慮這個(如果存在in out):

public class INewList<in out T> 
{ 
    public T DoIt(T item); 
} 

這將是不可能滿足,因爲人們期待的INewList<T>將與這兩個較窄和較寬的類型接口兼容。

考慮INewList<Feline>

如果入/出兩個可能,這個接口將相當於INewList<Animal>但這將是無效的對位,因爲這將允許你擴大至類型參數:

... DoIt(Animal item) 

這將無法正常工作,因爲那意味着您可以傳入一個new Dog()實例,其中Feline從原始界面中預計得到。

同樣,在對出位置相反的,因爲這將允許:

Puma DoIt(...) 

這將是無效的,因爲原來的接口可以傳回任何貓科動物,不一定是彪馬。

+0

對不起,我看到@Jason已經回答之前正在回答我的答案。 –

+0

不要道歉:-)總是很高興有一個不同的方式相同的事情。 –

+0

@James Michael Hare:哈!我提出了我的答案,包括一個沒有看到你的貓/狗的例子! – jason