泛型介面中的變異數 (C# 和 Visual Basic)
.NET Framework 4 針對數個現有的泛型介面加入了變異數 (Variance) 支援。 變異數支援讓實作這些介面的類別可以進行隱含轉換。 下列介面現在已經是 Variant:
IEnumerable<T> (T 為 Covariant)
IEnumerator<T> (T 為 Covariant)
IQueryable<T> (T 為 Covariant)
IGrouping<TKey, TElement> (TKey 和 TElement 為 Covariant)
IComparer<T> (T 為 Contravariant)
IEqualityComparer<T> (T 為 Contravariant)
IComparable<T> (T 為 Contravariant)
共變數允許方法具有與介面之泛型型別參數所定義的傳回型別相比,其衍生程度較大的傳回型別。 為了說明共變數功能,請考慮下列泛型介面:IEnumerable<Object> 和 IEnumerable<String> (在 Visual Basic 中則為 IEnumerable(Of Object) 和 IEnumerable(Of String))。 IEnumerable<String> (在 Visual Basic 中則為 IEnumerable(Of String)) 介面不會繼承 IEnumerable<Object> 介面 (在 Visual Basic 中則為 IEnumerable(Of Object)), 但是 String 型別則會繼承 Object 型別,而且可能需要在某些情況下將這些介面的物件指派給彼此。 請參考下列程式碼範例中的示範。
Dim strings As IEnumerable(Of String) = New List(Of String)
Dim objects As IEnumerable(Of Object) = strings
IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;
在舊版 .NET Framework 中,這個程式碼會在 C# 以及使用 Option Strict On 的 Visual Basic 中造成編譯錯誤。 但是,如前面範例所示,您現在可以使用 strings 取代 objects,因為 IEnumerable<T> 介面為 Covariant。
Contravariance 允許方法具有與介面之泛型參數指定的引數型別相比,其衍生程度較小的引數型別。 為了說明 Contravariance,假設您已經建立 BaseComparer 類別要與 BaseClass 類別的執行個體做比較。 BaseComparer 類別會實作 IEqualityComparer<BaseClass> (在 Visual Basic 中則為 IEqualityComparer(Of BaseClass)) 介面。 由於 IEqualityComparer<T> 介面現在是 Contravariant,因此您可以使用 BaseComparer 來比較繼承 BaseClass 類別的類別執行個體。 請參考下列程式碼範例中的示範。
' Simple hierarchy of classes.
Class BaseClass
End Class
Class DerivedClass
Inherits BaseClass
End Class
' Comparer class.
Class BaseComparer
Implements IEqualityComparer(Of BaseClass)
Public Function Equals1(ByVal x As BaseClass,
ByVal y As BaseClass) As Boolean _
Implements IEqualityComparer(Of BaseClass).Equals
Return (x.Equals(y))
End Function
Public Function GetHashCode1(ByVal obj As BaseClass) As Integer _
Implements IEqualityComparer(Of BaseClass).GetHashCode
Return obj.GetHashCode
End Function
End Class
Sub Test()
Dim baseComparer As IEqualityComparer(Of BaseClass) = New BaseComparer
' Implicit conversion of IEqualityComparer(Of BaseClass) to
' IEqualityComparer(Of DerivedClass).
Dim childComparer As IEqualityComparer(Of DerivedClass) = baseComparer
End Sub
// 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# 和 Visual Basic)。
在泛型介面中,僅支援參考型別的變異數。 實值型別不支援變異數。 例如,無法將 IEnumerable<int> (在 Visual Basic 中則為 IEnumerable(Of Integer)) 隱含轉換為 IEnumerable<object> (在 Visual Basic 中則為 IEnumerable(Of Object)),因為整數是由實值型別所表示。
Dim integers As IEnumerable(Of Integer) = New List(Of Integer)
' The following statement generates a compiler error
' with Option Strict On, because Integer is a value type.
' Dim objects As IEnumerable(Of Object) = integers
IEnumerable<int> integers = new List<int>();
// The following statement generates a compiler errror,
// because int is a value type.
// IEnumerable<Object> objects = integers;
同樣重要的是,請記得實作 Variant 介面的類別仍然為非變異 (Invariant)。 例如,雖然 List<T> 會實作 Covariant 介面 IEnumerable<T>,但是您無法將 List<Object> 隱含轉換為 List<String> (在 Visual Basic 中,則是無法將 List(Of Object) 隱含轉換為 List(Of String))。 這會在以下程式碼範例中說明。
' The following statement generates a compiler error
' because classes are invariant.
' Dim list As List(Of Object) = New List(Of String)
' You can use the interface object instead.
Dim listObjects As IEnumerable(Of Object) = New List(Of String)
// 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>();
請參閱
參考
針對泛型集合使用介面中的變異數 (C# 和 Visual Basic)