2012-12-27 46 views
4

可能重複的範圍之外:
Does C# support return type covariance?
Why can’t I implement an Interface this way?使用協方差的IEnumerable <T>

考慮以下幾點:

public interface IAnimal { 
} 

public class Animal : IAnimal { 
} 

public interface ICage { 
    IAnimal SomeAnimal {get;} 
} 

public class Cage : ICage{ 
    public Animal SomeAnimal { get; set; } 
} 

我已經讀了很多東西在co IEnumerable的方差和逆變,但我不知道如何讓上面的代碼工作。我收到錯誤「Cage不實現接口成員IAnimal」。由於它定義了動物,它比IAnimal更加定義,似乎協變應該照顧我。

我錯過了什麼?提前致謝。

+3

'public Animal {get;組; }'不應該編譯 - 你缺少名稱或返回類型。 –

+0

@Damien_The_Unbeliever謝謝,修正。 – manu08

+0

我相信內置支持(迄今爲止)只處理泛型類型參數。 –

回答

2

響應來自埃裏克利珀,報之以我問同樣的問題在這裏: Why can't I implement an Interface this way?

C#不支持返回類型的協方差爲 接口實現或虛擬方法覆蓋的目的。詳情請參見本 問題:

Does C# support return type covariance?

C#不支持構建wtih引用類型爲 類型參數的爲C#4

和通用協方差和接口 和委託類型逆變在將返回引用類型的方法 轉換爲返回類型爲 兼容引用類型的委託類型時,C#支持返回類型協方差。 (和同樣支持參數類型 逆變。)

如果這個問題你感興趣,我已經寫了許多文章討論 方差,C#語言不和不支持 各種版本。見

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/

瞭解詳情。

6

這在C#中目前不可行。

從理論上講,語言設計者可以添加它,但他們還沒有[尚未]。他們可能會或可能不會決定將其添加到潛在的未來版本的C#中。

最好的解決方法可能會是:

public class Cage : ICage 
{ 
    public Animal SomeAnimal { get; set; } 

    IAnimal ICage.SomeAnimal 
    { 
     get { return SomeAnimal } 
    } 
} 
+0

很好的答案。我選擇了Dave的,因爲他直接鏈接到EricL給更多的背景。 – manu08

2
public interface IAnimal { 
} 

public class Animal : IAnimal { 
} 

public interface ICage { 
    IAnimal SomeAnimal {get;} 
} 

public class Cage : ICage{ 
    public Animal SomeAnimal { get; set; } 
} 

public class AnotherAnimal : IAnimal { 
} 

Cage c = new Cage(); 
ICage ic = (ICage)c; 
ic.Animal = new AnotherAnimal(); 

這將是無效的,因爲AnotherAnimal實現IAnimal,但它不是一個Animal

EDIT

上述只會是相關的,如果有一個在接口中定義的設置器。因爲沒有,這裏的正確答案是在C#中無法實現所需的功能;它是一種不包含在該語言中的功能。

+0

'ICage'的財產在OP中沒有一個setter。 – Servy

+0

是真的,沒有setter這不會是一個問題,應該允許,但Eric Lippert的文章說,它只是不支持在C#中。 – samandmoore

+0

是的,我知道這一點,但沒有一個是你的答案。 OP特別確保'ICage' *不具有吸氣劑,這在邏輯上會使得使用協變性成爲可能,它僅僅是該語言中未包括的一個特徵。因此,答案是,「這是一個未包含在該語言中的特徵」,而不是「由於[...]而無法執行」。 – Servy

2

要獲得協方差,你應該有這樣的事情:

public interface IAnimal { 
} 

public class Lion : IAnimal {} 
public class Sheep : IAnimal {} 

// note the "out" on the T type parameter 
public interface ICage<out T> where T:IAnimal { 
    T SomeAnimal {get;} 
} 

public class Cage<T> : ICage<T> where T:IAnimal { 
    public T SomeAnimal { get; set; } 
} 

你現在可以這樣做:

// without covariance on ICage you can't assign a 'Cage<Sheep>' to 'ICage<IAnimal>' 
ICage<IAnimal> sheeps = new Cage<Sheep>() {SomeAnimal=new Sheep()}; 
ICage<IAnimal> lions = new Cage<Lion>() {SomeAnimal=new Lion()}; 

或本(與綿羊和網箱的兩個機架產生的Cage<IAnimals>異構名單這是一個等效但可能更有用的例子:

// without covariance on ICage it errors: cannot convert from 'Cage<Sheep>' to 'ICage<IAnimal>' 
var zoo = new List<ICage<IAnimal>>{ 
    new Cage<Sheep> {SomeAnimal=new Sheep()}, 
    new Cage<Lion> {SomeAnimal=new Lion()}, 
}; 

如果您嘗試從ICage的聲明中刪除out,您將看到區別。