Delen via


Afwijking in algemene interfaces (C#)

.NET Framework 4 heeft variantieondersteuning geïntroduceerd voor verschillende bestaande algemene interfaces. Variantieondersteuning maakt impliciete conversie mogelijk van klassen die deze interfaces implementeren.

Vanaf .NET Framework 4 zijn de volgende interfaces variant:

Vanaf .NET Framework 4.5 zijn de volgende interfaces variant:

Met covariantie kan een methode een meer afgeleid retourtype hebben dan dat is gedefinieerd door de algemene typeparameter van de interface. Als u de covariantiefunctie wilt illustreren, kunt u de volgende algemene interfaces overwegen: IEnumerable<Object> en IEnumerable<String>. De IEnumerable<String> interface neemt de IEnumerable<Object> interface niet over. Het String type neemt echter het Object type over en in sommige gevallen wilt u mogelijk objecten van deze interfaces aan elkaar toewijzen. Dit wordt weergegeven in het volgende codevoorbeeld.

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

In eerdere versies van .NET Framework veroorzaakt deze code een compilatiefout in C# en, indien Option Strict ingeschakeld, in Visual Basic. Maar nu kunt u in plaats van objects, zoals wordt weergegeven in het vorige voorbeeld, omdat strings de IEnumerable<T> interface covariant is.

Met contravariantie kan een methode argumenttypen hebben die minder zijn afgeleid dan die zijn opgegeven door de algemene parameter van de interface. Als u de contravariantie wilt illustreren, gaat u ervan uit dat u een BaseComparer klasse hebt gemaakt om exemplaren van de BaseClass klasse te vergelijken. Met de klasse BaseComparer wordt de IEqualityComparer<BaseClass>-interface geïmplementeerd. Omdat de IEqualityComparer<T> interface nu contravariant is, kunt u exemplaren BaseComparer van klassen vergelijken die de BaseClass klasse overnemen. Dit wordt weergegeven in het volgende codevoorbeeld.

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

Zie Afwijking gebruiken in interfaces voor algemene verzamelingen (C#) voor meer voorbeelden.

Variantie in algemene interfaces wordt alleen ondersteund voor referentietypen. Waardetypen bieden geen ondersteuning voor variantie. Kan bijvoorbeeld IEnumerable<int> niet impliciet worden geconverteerd naar IEnumerable<object>, omdat gehele getallen worden vertegenwoordigd door een waardetype.

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

Het is ook belangrijk te onthouden dat klassen die variantinterfaces implementeren, nog steeds invariant zijn. Hoewel de covariant-interface IEnumerable<T>bijvoorbeeld List<T> wordt geïmplementeerd, kunt u niet impliciet converteren List<String> naar List<Object>. Dit wordt geïllustreerd in het volgende codevoorbeeld.

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

Zie ook