泛型介面中的變異數 (C# 和 Visual Basic)

.NET Framework 4 針對數個現有的泛型介面加入了變異數 (Variance) 支援。 變異數支援讓實作這些介面的類別可以進行隱含轉換。 下列介面現在已經是 Variant:

共變數允許方法具有與介面之泛型型別參數所定義的傳回型別相比,其衍生程度較大的傳回型別。 為了說明共變數功能,請考慮下列泛型介面: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)

概念

建立 Variant 泛型介面 (C# 和 Visual Basic)

泛型介面

委派中的變異數 (C# 和 Visual Basic)