Wariancja w interfejsach ogólnych (Visual Basic)
Program .NET Framework 4 wprowadził obsługę wariancji dla kilku istniejących interfejsów ogólnych. Obsługa wariancji umożliwia niejawną konwersję klas implementujących te interfejsy. Następujące interfejsy są teraz wariantami:
IEnumerable<T> (T jest kowariantny)
IEnumerator<T> (T jest kowariantny)
IQueryable<T> (T jest kowariantny)
IGrouping<TKey,TElement> (
TKey
iTElement
są kowariantne)IComparer<T> (T jest kontrawariantny)
IEqualityComparer<T> (T jest kontrawariantny)
IComparable<T> (T jest kontrawariantny)
Kowariancja zezwala metodzie na bardziej pochodny typ zwracany niż zdefiniowany przez ogólny parametr typu interfejsu. Aby zilustrować funkcję kowariancji, rozważ następujące interfejsy ogólne: IEnumerable(Of Object)
i IEnumerable(Of String)
. Interfejs IEnumerable(Of String)
nie dziedziczy interfejsu IEnumerable(Of Object)
. Jednak String
typ dziedziczy Object
typ, a w niektórych przypadkach można przypisać do siebie obiekty tych interfejsów. Jest to pokazane w poniższym przykładzie kodu.
Dim strings As IEnumerable(Of String) = New List(Of String)
Dim objects As IEnumerable(Of Object) = strings
We wcześniejszych wersjach programu .NET Framework ten kod powoduje błąd kompilacji w języku Visual Basic za pomocą polecenia Option Strict On
. Teraz można jednak użyć wartości strings
zamiast objects
, jak pokazano w poprzednim przykładzie, ponieważ IEnumerable<T> interfejs jest kowariantny.
Kontrawariancja umożliwia metodzie posiadanie typów argumentów, które są mniej pochodne niż określone przez ogólny parametr interfejsu. Aby zilustrować kontrawariancję, załóżmy, że utworzono klasę BaseComparer
do porównywania wystąpień BaseClass
klasy. Klasa BaseComparer
implementuje interfejs IEqualityComparer(Of BaseClass)
. IEqualityComparer<T> Ponieważ interfejs jest teraz kontrawariantny, można użyć BaseComparer
do porównania wystąpień klas, które dziedziczą klasęBaseClass
. Jest to pokazane w poniższym przykładzie kodu.
' 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
Aby uzyskać więcej przykładów, zobacz Using Variance in Interfaces for Generic Collections (Visual Basic) (Używanie wariancji w interfejsach dla kolekcji ogólnych (Visual Basic).
Wariancja w interfejsach ogólnych jest obsługiwana tylko w przypadku typów referencyjnych. Typy wartości nie obsługują wariancji. Na przykład IEnumerable(Of Integer)
nie można niejawnie przekonwertować na IEnumerable(Of Object)
wartość , ponieważ liczby całkowite są reprezentowane przez typ wartości.
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
Należy również pamiętać, że klasy implementujące interfejsy wariantów są nadal niezmienne. Na przykład chociaż List<T> implementuje kowariantny interfejs IEnumerable<T>, nie można niejawnie przekonwertować List(Of Object)
na List(Of String)
. Jest to pokazane w poniższym przykładzie kodu.
' 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)