上面示例中的Farm<T>類以及本章前面介紹的其他幾個類都繼承自一個泛型類型。
在Farm<T>中,這個類型是一個接口IEnumerable<T>。
這里Farm<T>在T上提供的約束也會在IEnumerable<T>中使用的T上添加一個額外的約束。
這可以用於限制未約束的類型,但是需要遵循一些規則。
首先,如果某個類型在它所繼承的基類型中受到了約束,該類型就不能“解除約束”。
也就是說,類型T在所繼承的基類型中使用時,該類型必須受到至少與基類型相同的約束。
例如,下面的代碼是正確的
class SuperFarm<T>:Farm<T>
where T:SuperCow
{
}
因為T在Farm<T>中被約束為Animal,把它約束為SuperCow,就是把T約束為這些值的一個子集,所以這段代碼可以正常運行。
但是,不會編譯下面的代碼
class SuperFarm<T>:Farm<T>
where T:struct
{
}
可以肯定地說,提供給SuperFarm<T>的類型T不能轉換為可由Farm<T>使用的T,所以代碼不會編譯。
甚至約束為超集的情況也會出現相同的問題:
class SuperFarm<T>:Farm<T>
where T:class //類約束
{
}
即使SuperFarm<T>允許有像Animal這樣的類型,Farm<T>中也不允許有滿足類約束的其他類型。
否則編譯就會失敗。
這個規則適用於本章前面介紹的所有約束類型。
另外,如果繼承了一個泛型類型,就必須提供所有必須的類型信息。
這可以使用其他泛型類型參數的形式來提供,如上所述,也可以顯式提供。
這也適用於繼承了泛型類型的非泛型類。
例如:
public class Cards:List<Card>,ICloneable
{
}
這是可行的
但下面的代碼會失敗
public class Cards:List<T>,ICloneable
因為沒有提供T的信息,所以不能編譯
注意:
如果給泛型類型提供了參數,例如,上面的List<Card>,就可以把類型引用為"關閉"。
同樣,繼承List<T>,就是繼承一個"打開"的泛型類型。