Rozptyl v obecných rozhraních (C#)

Rozhraní .NET Framework 4 zavedlo podporu odchylek pro několik existujících obecných rozhraní. Podpora rozptylu umožňuje implicitní převod tříd, které implementují tato rozhraní.

Počínaje rozhraním .NET Framework 4 jsou následující rozhraní variantou:

Počínaje rozhraním .NET Framework 4.5 jsou varianta následujících rozhraní:

Kovariance umožňuje metodě mít odvozenější návratový typ, než který definuje parametr obecného typu rozhraní. Chcete-li ilustrovat kovarianci funkce, zvažte tato obecná rozhraní: IEnumerable<Object> a IEnumerable<String>. Rozhraní IEnumerable<String> nedědí IEnumerable<Object> rozhraní. String Typ však zdědí Object typ a v některých případech můžete chtít přiřadit objekty těchto rozhraní k sobě navzájem. To je znázorněno v následujícím příkladu kódu.

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

V dřívějších verzích rozhraní .NET Framework tento kód způsobí chybu kompilace v jazyce C# a pokud Option Strict je zapnutá, v jazyce Visual Basic. Nyní ale můžete místo stringsobjects, jak je znázorněno v předchozím příkladu, protože IEnumerable<T> rozhraní je kovariantní.

Kontravariance umožňuje metodě mít typy argumentů, které jsou méně odvozeny, než které specifikuje obecný parametr rozhraní. Chcete-li ilustrovat kontravariance, předpokládejme, že jste vytvořili BaseComparer třídu pro porovnání instancí BaseClass třídy. Třída BaseComparer implementuje rozhraní IEqualityComparer<BaseClass>. Vzhledem k tomu, že IEqualityComparer<T> rozhraní je nyní kontravariantní, můžete použít BaseComparer k porovnání instancí tříd, které dědí BaseClass třídu. To je znázorněno v následujícím příkladu kódu.

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

Další příklady najdete v tématu Použití rozptylu v rozhraních pro obecné kolekce (C#).

Variance v obecných rozhraních je podporována pouze pro odkazové typy. Typy hodnot nepodporují odchylku. Například IEnumerable<int> nelze implicitně převést na IEnumerable<object>, protože celá čísla jsou reprezentována typem hodnoty.

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

Je také důležité si uvědomit, že třídy, které implementují variantní rozhraní, jsou stále invariantní. Ačkoli například List<T> implementuje kovariantní rozhraní IEnumerable<T>, nelze implicitně převést List<String> na List<Object>. To je znázorněno v následujícím příkladu kódu.

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

Viz také