這段代碼在Visual Studio中進行編譯,什麼是它的使用這個複習泛型類的用法是什麼?
public class MyClass<T>
where T : MyClass<T>
注where T : MyClass<T>
這段代碼在Visual Studio中進行編譯,什麼是它的使用這個複習泛型類的用法是什麼?
public class MyClass<T>
where T : MyClass<T>
注where T : MyClass<T>
這是recurring template pattern,通常用於基類可以靜態引用其真實類型。這是在試圖保留類型安全,這樣的參數或在基類返回簡稱值跟蹤當前的類型層次結構中的如
public class Animal<T> where T : Animal<T>
{
public abstract T GiveBirth();
}
public class Cat : Animal<Cat>
{
public override Cat GiveBirth() { return new Cat(); }
}
不帶類型參數的Animal
基類的方法只會做能夠將GiveBirth
的返回類型定義爲Animal
,這可能會降低客戶端的類型安全性。
如果您控制整個層次結構並確保類提供正確的類型參數,但它可能是可接受的,但請注意它可能被濫用,例如,
public class Cat : Animal<Dog> { ... }
另一個缺點是任何客戶端需要考慮到一般類型參數的,如果他們想要施加到基類例如
public static void Feed<T>(Animal<T> animal) where T : Animal<T> { ... }
public static void Feed<T>(T animal) where T : Animal<T> { ... }
它看起來是保證類型是二維的(如果這個詞在這裏是有道理的)。
例如:Node<int>
最終將成爲Node<Node<int>>
。
我覺得編譯器會顯示錯誤,因爲T IN節點
這是一個奇怪的循環模式的例子。 Eric Lippert對此有an excellent article,包括爲什麼你通常應該避免它。
它可能被擴展這樣的:
public class MyChild : MyClass<MyChild>
模式並沒有真正的線索,你爲爲什麼你想要這個通用的。這與大多數泛型/約束不同......例如。如果我有List<Giraffe>
我可以看到關係;如果我有MyGeneric<T, U> where T : IComparer<U>
,我可以看到T
會做什麼。用T : MyClass<T>
,我真的沒有關於這裏的關係或用法的提示。也許有一個......
abstract T Instance { get; }
...你想擁有的MyChild
更強打字在MyChild
的情況。
作爲一個例子,爲什麼這不是很好,你可以有MyOtherClass : MyClass<MyChild>
,或者你可以有MyGrandchild : MyChild
,這兩者都可能是你試圖強制執行的。
對於類型,這將僅由一個抽象基類具有繼承的單層,使用所描述的圖案將使得有可能爲抽象基類型包括,當被叫的任何構件上的方法派生類型,將返回該派生類型的成員。這可能是一個有用的設計功能,允許使用比其他方式更清晰的主叫方代碼。這種設計最大的問題是,因爲.NET不支持協變泛型類參數,所以這種方法不適用於多層繼承。
鑑於abstract class AnimalBase<T> where T:AnimalBase<T>
,與法T Clone()
和class Cat: AnimalBase<Cat>
,代碼可以說var newCat = someCat.Clone(); newCat.Meow();
而不是說var newCat = (Cat)(someCat.Clone()); newCat.Meow();
。不幸的是,沒有辦法有SiameseCat
正確地從Cat
派生出來,因爲唯一的方法是有mySiameseCat.Clone()
;返回一個SiameseCat
將有SiameseCat
派生自AnimalBase<SiameseCat>
,但這將阻止它從Cat
派生。
如果不是有一個類限制到它自己的類型,而是定義一個通用接口並限制它,可以避免這樣的困難。在執行IAnimal<SiameseCat>
時,SiameseCat
從Cat
派生將沒有問題。此外,接口是協變的,因此實現IAnimal<SiameseCat>
的類型也可以隱含地實現IAnimal<Cat>
[如果Cat
是一個抽象類型,它沒有實現接口本身]。每個派生類都必須提供它自己的實現,其返回值隨通用類型參數而變化,但從調用者的角度來看,接口類型可以與派生類完美行爲。
感謝了很多,但在什麼樣的問題,我們應該使用這種模式? – RezaRahmati
@RezaRahmati - 我已經添加了一個例子,如果有幫助? – Lee