Variação em interfaces genéricas (Visual Basic)
O .NET Framework 4 introduziu o suporte à variação para diversas interfaces genéricas existentes. O suporte à variação possibilita a conversão implícita de classes que implementam essas interfaces. As seguintes interfaces agora são variantes:
IEnumerable<T> (T é covariante)
IEnumerator<T> (T é covariante)
IQueryable<T> (T é covariante)
IGrouping<TKey,TElement> (
TKey
eTElement
são covariantes)IComparer<T> (T é contravariante)
IEqualityComparer<T> (T é contravariante)
IComparable<T> (T é contravariante)
A covariância permite que um método tenha um tipo de retorno mais derivados que aquele definidos pelo parâmetro de tipo genérico da interface. Para ilustrar o recurso de covariância, considere estas interfaces genéricas: IEnumerable(Of Object)
e IEnumerable(Of String)
. A interface IEnumerable(Of String)
não herda a interface IEnumerable(Of Object)
. No entanto, o tipo String
herda o tipo Object
e, em alguns casos, talvez você queira atribuir objetos dessas interfaces uns aos outros. Isso é mostrado no exemplo de código a seguir.
Dim strings As IEnumerable(Of String) = New List(Of String)
Dim objects As IEnumerable(Of Object) = strings
Em versões anteriores do .NET Framework, esse código causa um erro de compilação no Visual Basic com Option Strict On
. Mas agora você pode usar strings
em vez de objects
, conforme mostrado no exemplo anterior, porque a interface IEnumerable<T> é covariante.
A contravariância permite que um método tenha tipos de argumentos menos derivados que aquele especificado pelo parâmetro genérico da interface. Para ilustrar a contravariância, suponha que você tenha criado uma classe BaseComparer
para comparar instâncias da classe BaseClass
. A classe BaseComparer
implementa a interface IEqualityComparer(Of BaseClass)
. Como a interface IEqualityComparer<T> agora é contravariante, você pode usar BaseComparer
para comparar instâncias de classes que herdam a classe BaseClass
. Isso é mostrado no exemplo de código a seguir.
' 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
Para ver mais exemplos, consulte Usar variação em interfaces para coleções genéricas (Visual Basic).
A variação em interfaces genéricas tem suporte somente para tipos de referência. Tipos de valor não dão suporte à variação. Por exemplo, IEnumerable(Of Integer)
não pode ser convertido implicitamente em IEnumerable(Of Object)
, porque inteiros são representados por um tipo de valor.
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
Também é importante lembrar que as classes que implementam interfaces variantes ainda são invariantes. Por exemplo, embora List<T> implemente a interface covariante IEnumerable<T>, você não pode converter implicitamente List(Of Object)
para List(Of String)
. Isso é ilustrado no exemplo de código a seguir.
' 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)