Partilhar via


Variância em interfaces genéricas (C#)

O .NET Framework 4 introduziu o suporte à variância para várias interfaces genéricas existentes. O suporte à variância permite a conversão implícita de classes que implementam essas interfaces.

A partir do .NET Framework 4, as seguintes interfaces são variantes:

A partir do .NET Framework 4.5, as seguintes interfaces são variantes:

A covariância permite que um método tenha um tipo de retorno mais derivado do que o definido pelo parâmetro de tipo genérico da interface. Para ilustrar o recurso de covariância, considere estas interfaces genéricas: IEnumerable<Object> e IEnumerable<String>. A IEnumerable<String> interface não herda a IEnumerable<Object> interface. No entanto, o String tipo herda o Object tipo e, em alguns casos, você pode querer atribuir objetos dessas interfaces uns aos outros. Isso é mostrado no exemplo de código a seguir.

IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;

Em versões anteriores do .NET Framework, esse código causa um erro de compilação em C# e, se Option Strict estiver ativado, no Visual Basic. Mas agora você pode usar strings em vez de objects, como mostrado no exemplo anterior, porque a IEnumerable<T> interface é covariante.

A contravariância permite que um método tenha tipos de argumento que são menos derivados do que o especificado pelo parâmetro genérico da interface. Para ilustrar a contravariância, suponha que você criou uma BaseComparer classe para comparar instâncias da BaseClass classe. A classe BaseComparer implementa a interface IEqualityComparer<BaseClass>. Como a IEqualityComparer<T> interface agora é contravariante, você pode usar BaseComparer para comparar instâncias de classes que herdam a BaseClass classe. Isso é mostrado no exemplo de código a seguir.

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

Para obter mais exemplos, consulte Usando variância em interfaces para coleções genéricas (C#).

A variância em interfaces genéricas é suportada apenas para tipos de referência. Os tipos de valor não suportam variância. Por exemplo, IEnumerable<int> não pode ser convertido implicitamente em IEnumerable<object>, porque inteiros são representados por um tipo de valor.

IEnumerable<int> integers = new List<int>();
// The following statement generates a compiler error,
// because int is a value type.
// IEnumerable<Object> objects = integers;

Também é importante lembrar que as classes que implementam interfaces variantes ainda são invariantes. Por exemplo, embora List<T> implemente a interface IEnumerable<T>covariante, você não pode converter List<String> implicitamente em List<Object>. Isso é ilustrado no exemplo de código a seguir.

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

Consulte também