.NET Framework 4 引進了數個現有泛型介面的變異數支援。 變異數支援可讓您隱含轉換實作這些介面的類別。
從 .NET Framework 4 開始,下列介面具有可變性:
IEnumerable<T> (T 是共變數)
IEnumerator<T> (T 是共變數)
IQueryable<T> (T 是共變數)
IGrouping<TKey,TElement> (
TKey和TElement是共變數)IComparer<T> (T 是反變數)
IEqualityComparer<T> (T 是反變數)
IComparable<T> (T 是反變數)
從 .NET Framework 4.5 開始,下列介面具有可變性:
IReadOnlyList<T> (T 是共變數)
IReadOnlyCollection<T> (T 是共變數)
協變性允許方法具有比介面的泛型型別參數所定義的更衍生的返回型別。 若要說明共變數功能,請考慮下列泛型介面: IEnumerable<Object> 和 IEnumerable<String>。 介面 IEnumerable<String> 不會繼承 IEnumerable<Object> 介面。 不過, String 此類型會繼承 Object 類型,在某些情況下,您可能會想要將這些介面的物件指派給彼此。 如下列程式代碼範例所示。
IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;
在舊版 .NET Framework 中,這段程式碼會在 C# 中造成編譯錯誤,如果 Option Strict 開啟,則在 Visual Basic 中也會如此。 但現在您可以使用 strings ,而不是 objects,如上一個範例所示,因為 IEnumerable<T> 介面是covariant。
反變形允許方法的引數類型比介面的泛型參數所指定的類型衍生程度更低。 為了說明反變數,假設您已建立類別 BaseComparer 來比較 類別的 BaseClass 實例。
BaseComparer 類別會實作 IEqualityComparer<BaseClass> 介面。 因為IEqualityComparer<T>介面現在是逆變型,因此您可以使用BaseComparer來比較繼承BaseClass類別的實例。 如下列程式代碼範例所示。
// Simple hierarchy of classes.
class BaseClass { }
class DerivedClass : BaseClass { }
// Comparer class.
class BaseComparer : IEqualityComparer<BaseClass>
{
public int GetHashCode(BaseClass baseInstance)
{
return baseInstance.GetHashCode();
}
public bool Equals(BaseClass x, BaseClass y)
{
return x == y;
}
}
class Program
{
static void Test()
{
IEqualityComparer<BaseClass> baseComparer = new BaseComparer();
// Implicit conversion of IEqualityComparer<BaseClass> to
// IEqualityComparer<DerivedClass>.
IEqualityComparer<DerivedClass> childComparer = baseComparer;
}
}
如需更多範例,請參閱 在泛型集合的介面中使用變數 (C#) 。
泛型介面的變異數只適用於參考類型。 實值類型不支援變異數。 例如, IEnumerable<int> 無法隱含轉換成 IEnumerable<object>,因為整數是由實值型別表示。
IEnumerable<int> integers = new List<int>();
// The following statement generates a compiler error,
// because int is a value type.
// IEnumerable<Object> objects = integers;
請務必記住,實作 Variant 介面的類別仍然不可變。 例如,雖然 List<T> 實作協變介面 IEnumerable<T>,但您無法將 List<String> 隱式轉換為 List<Object>。 下列程式代碼範例會說明這一點。
// The following line generates a compiler error
// because classes are invariant.
// List<Object> list = new List<String>();
// You can use the interface object instead.
IEnumerable<Object> listObjects = new List<String>();