Variancia az általános felületeken (C#)
.NET-keretrendszer 4 számos meglévő általános adapter varianciáját támogatja. A variancia-támogatás lehetővé teszi az ezen interfészeket megvalósító osztályok implicit átalakítását.
A .NET-keretrendszer 4-től kezdve a következő interfészek variánsok:
IEnumerable<T> (T kovariant)
IEnumerator<T> (T kovariant)
IQueryable<T> (T kovariant)
IGrouping<TKey,TElement> (
TKey
ésTElement
kovariant)IComparer<T> (T is contravariant)
IEqualityComparer<T> (T is contravariant)
IComparable<T> (T is contravariant)
A .NET-keretrendszer 4.5-től kezdve a következő interfészek variálnak:
IReadOnlyList<T> (T kovariant)
IReadOnlyCollection<T> (T kovariant)
A kovariancia lehetővé teszi, hogy egy metódus származtatottabb visszatérési típussal rendelkezzen, mint amelyet az interfész általános típusparamétere határoz meg. A kovariancia funkció szemléltetéséhez vegye figyelembe az alábbi általános felületeket: IEnumerable<Object>
és IEnumerable<String>
. A IEnumerable<String>
felület nem örökli a IEnumerable<Object>
felületet. A String
típus azonban örökli a Object
típust, és bizonyos esetekben érdemes lehet ezeknek a felületeknek az objektumait egymáshoz rendelni. Ez az alábbi példakódban látható.
IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;
A .NET-keretrendszer korábbi verzióiban ez a kód fordítási hibát okoz A C# és ha Option Strict
be van kapcsolva, a Visual Basicben. Most azonban használhatja strings
objects
ahelyett, hogy az előző példában látható módon, mert a IEnumerable<T> felület kovariant.
A contravariance lehetővé teszi, hogy egy metódus olyan argumentumtípusokat használjon, amelyek kevésbé származnak, mint a felület általános paramétere által megadottak. A contravariance szemléltetéséhez tegyük fel, hogy létrehozott egy osztályt BaseComparer
az BaseClass
osztály példányainak összehasonlításához. Az BaseComparer
osztály megvalósítja az IEqualityComparer<BaseClass>
felületet. Mivel a IEqualityComparer<T> felület most már contravariant, az osztályt öröklő BaseClass
osztályok példányainak összehasonlítására használhatóBaseComparer
. Ez az alábbi példakódban látható.
// 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;
}
}
További példákért lásd: Variancia használata általános gyűjteményekhez készült felületekben (C#).
Az általános felületek varianciája csak referenciatípusok esetén támogatott. Az értéktípusok nem támogatják a varianciát. Nem konvertálható IEnumerable<object>
például IEnumerable<int>
implicit módon, mert az egész számokat értéktípus jelöli.
IEnumerable<int> integers = new List<int>();
// The following statement generates a compiler error,
// because int is a value type.
// IEnumerable<Object> objects = integers;
Azt is fontos megjegyezni, hogy a variáns interfészeket megvalósító osztályok még mindig invariánsak. Például, bár List<T> implementálja a kovariant felületet IEnumerable<T>, nem konvertálható List<String>
List<Object>
implicit módon. Ezt az alábbi példakód szemlélteti.
// 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>();