[英]C# polymorphism and generics type matching error
我有一個類似的結構
enum AnimalType {dog, cat}
class Animal{}
class Dog : Animal {}
class Cat : Animal {}
class Vet<T> where T : Animal {}
class DogVet : Vet<Dog> {}
class CatVet : Vet<Cat> {}
為什么我不能分配這個?
...
Vet<Animal> myVet = new DogVet();
...
為什么我不能像這樣向Dictionary
添加元素?
...
Dictionary<AnimalType, Vet<Animal>> _vetList = new Dictionary<AnimalType, Vet<Animal>>();
_vetList.Add(AnimalType.dog, new DogVet());
...
這應該怎么做?
這是一個經典的協方差問題。 Vet<Dog>
不是Vet<Animal>
。 如果繼續類比, Vet<Dog>
只能治療狗。 您不能將其用作可以治療任何動物的獸醫。
假設您有一個Treat
函數:
public void Treat<T>(T patient) {}
現在,如果Vet<Dog>
是Vet<Animal>
那么這將是可能的:
Vet<Animal> dogVet = new Vet<Dog>();
dogVet.Treat(new Cat()); // but I can only treat dogs!!!
為此,您需要協變(或逆變)類型參數。 不幸的是,您只能在接口或委托上指定這些,而不能在類上指定。 獲得所需內容的一種方法是在 Vet 類之上創建一個接口,如下所示:
// Not sure what you need this enum for, but OK...
enum AnimalType {dog, cat}
class Animal{}
class Dog : Animal {}
class Cat : Animal {}
// Create an interface with covariant parameter
// i.e. an IVet<T> is also an IVet<Animal> for all T deriving from Animal.
interface IVet<out T> where T : Animal {}
// Made Vet abstract. You can still use this to provide base implementations for concrete Vets.
abstract class Vet<T> : IVet<T> where T : Animal {}
class DogVet : Vet<Dog> {}
class CatVet : Vet<Cat> {}
static void Main()
{
// Must use the interface here.
IVet<Animal> vet = new DogVet();
}
老實說,您發布的代碼讓我懷疑問題是否不在於您的代碼設計而不是語法。
請注意,盡管可以編譯,但 D Stanley 的回答中的警告是有效的。 例如,您現在無法向接口添加方法void Treat(T patient)
。
當您發現自己正在檢查運行時類型,或者因為您的基類定義了一個以T
作為參數的函數並且它不會接受派生類中帶有Dog
的實現而導致編譯錯誤時,您應該重新設計您的程序。 事實上,我現在會認真考慮這一點。
這里的代碼味道是你在Animal
上有一個繼承樹,你正在用另一個繼承樹Vet
模仿它。 未能為新的Animal
衍生物添加適當的Vet
衍生物會讓您頭疼。
主要原因是泛型不支持協方差。 以下信息摘自 Jon Skeet 的書 c# In Depth。
簡短的回答是因為如果允許,這將是合法但無效的。
Dictionary<AnimalType, Vet<Animal>> _vetList = new Dictionary<AnimalType, Vet<Cat>>();
_vetList.Add(AnimalType.Dog, new Vet<Dog>());
由於字典被告知它使用的是動物,但實際對象是貓,因此它會在運行時失敗。 再次根據這本書,設計人員寧願編譯時失敗而不是運行時崩潰,因此在嘗試執行此操作時會出現錯誤。
這稱為協方差,此功能僅在委托和接口中受支持。
例如:
// Covariance
IEnumerable<object> x = new List<string>();
在 MSDN 中了解有關協方差和逆變的更多信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.