Variance dans les interfaces génériques (C# et Visual Basic)

.NET Framework 4 apporte une prise en charge de la variance pour plusieurs interfaces génériques existantes. La prise en charge de la variance permet la conversion implicite des classes qui implémentent ces interfaces. Les interfaces suivantes sont maintenant variantes :

La covariance autorise une méthode à avoir un type de retour plus dérivé que celui défini par le paramètre de type générique de l'interface. Pour illustrer la fonctionnalité de covariance, considérez ces interfaces génériques : IEnumerable<Object> et IEnumerable<String> (IEnumerable(Of Object) et IEnumerable(Of String) en Visual Basic). L'interface IEnumerable<String> (IEnumerable(Of String) en Visual Basic) n'hérite pas de l'interface IEnumerable<Object> (IEnumerable(Of Object) en Visual Basic). Toutefois, le type String hérite du type Object, et dans certains cas, vous pouvez assigner des objets de ces interfaces de l'un à l'autre. Ceci est illustré dans l'exemple de code suivant.

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;

Dans les versions antérieures du .NET Framework, ce code provoque une erreur de compilation en C# et en Visual Basic avec Option Strict On. Mais maintenant, vous pouvez utiliser strings au lieu d'objects, comme indiqué dans l'exemple précédent, parce que l'interface IEnumerable est covariante.

La contravariance permet à une méthode d'avoir des types d'argument moins dérivés que ceux spécifiés par le paramètre générique de l'interface. Pour illustrer la contravariance, supposez que vous avez créé une classe BaseComparer pour comparer des instances de la classe BaseClass. La classe BaseComparer implémente l'interface IEqualityComparer<BaseClass> (IEqualityComparer(Of BaseClass) en Visual Basic). Étant donné que l'interface IEqualityComparer est maintenant contravariante, vous pouvez utiliser BaseComparer pour comparer des instances des classes qui héritent de la classe BaseClass. Ceci est illustré dans l'exemple de code suivant.

' 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;
    }
}

Pour plus d'exemples, consultez Utilisation de la variance dans les interfaces pour les collections génériques (C# et Visual Basic).

La variance dans les interfaces génériques est prise en charge uniquement pour les types référence. Les types valeur ne prennent pas en charge la variance. Par exemple, IEnumerable<int> (IEnumerable(Of Integer) en Visual Basic) ne peut pas être converti implicitement en IEnumerable<object> (IEnumerable(Of Object) en Visual Basic) car les entiers sont représentés par un type valeur.

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;

Il est également important de se souvenir que les classes qui implémentent des interfaces variantes sont toujours invariantes. Par exemple, bien que List implémente l'interface covariante IEnumerable, vous ne pouvez pas convertir implicitement List<Object> en List<String> (List(Of Object) en List(Of String) en Visual Basic). L'exemple de code suivant l'illustre.

' 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>();

Voir aussi

Référence

Utilisation de la variance dans les interfaces pour les collections génériques (C# et Visual Basic)

Concepts

Création d'interfaces génériques de type variant (C# et Visual Basic)

Interfaces génériques

Variance dans les délégués (C# et Visual Basic)