Varians i allmänna gränssnitt (Visual Basic)
.NET Framework 4 introducerade variansstöd för flera befintliga generiska gränssnitt. Avvikelsestöd möjliggör implicit konvertering av klasser som implementerar dessa gränssnitt. Följande gränssnitt är nu variant:
IEnumerable<T> (T är covariant)
IEnumerator<T> (T är covariant)
IQueryable<T> (T är covariant)
IGrouping<TKey,TElement> (
TKey
ochTElement
är covariant)IComparer<T> (T är kontravariant)
IEqualityComparer<T> (T är kontravariant)
IComparable<T> (T är kontravariant)
Med kovarians kan en metod ha en mer härledd returtyp än den som definieras av den generiska typparametern i gränssnittet. För att illustrera covariance-funktionen bör du överväga dessa allmänna gränssnitt: IEnumerable(Of Object)
och IEnumerable(Of String)
. Gränssnittet IEnumerable(Of String)
ärver IEnumerable(Of Object)
inte gränssnittet. Men typen String
ärver Object
typen, och i vissa fall kanske du vill tilldela objekt av dessa gränssnitt till varandra. Detta visas i följande kodexempel.
Dim strings As IEnumerable(Of String) = New List(Of String)
Dim objects As IEnumerable(Of Object) = strings
I tidigare versioner av .NET Framework orsakar den här koden ett kompileringsfel i Visual Basic med Option Strict On
. Men nu kan du använda strings
i stället för objects
, som du ser i föregående exempel, eftersom IEnumerable<T> gränssnittet är covariant.
Contravariance tillåter att en metod har argumenttyper som är mindre härledda än den som anges av den generiska parametern i gränssnittet. Anta att du har skapat en BaseComparer
klass för att jämföra instanser av BaseClass
klassen för att illustrera kontravarians. Klassen BaseComparer
implementerar gränssnittet IEqualityComparer(Of BaseClass)
. IEqualityComparer<T> Eftersom gränssnittet nu är kontravariant kan du använda BaseComparer
för att jämföra instanser av klasser som ärver BaseClass
klassen. Detta visas i följande kodexempel.
' 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
Fler exempel finns i Använda varians i gränssnitt för generiska samlingar (Visual Basic).
Varians i allmänna gränssnitt stöds endast för referenstyper. Värdetyper stöder inte varians. Det IEnumerable(Of Integer)
går till exempel inte att implicit konvertera till IEnumerable(Of Object)
, eftersom heltal representeras av en värdetyp.
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
Det är också viktigt att komma ihåg att klasser som implementerar variantgränssnitt fortfarande är invarianta. Även om List<T> du till exempel implementerar det covarianta gränssnittet IEnumerable<T>kan du inte implicit konvertera List(Of Object)
till List(Of String)
. Detta illustreras i följande kodexempel.
' 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)