In deel I hebben we bekeken hoe we lijsten met specifieke objecten konden hanteren als een lijst van gegeneraliseerde objecten We noemden deze vorm van variantie Covariant gedrag. Het omgekeerde is echter ook mogelijk. In dat geval spreken we van Contravariant gedrag. Het nut hiervan zal ik nu bespreken. Bekijk weer de volgende hiërarchie.
interface IProduct
{
string Merk { get; }
}
class Melk : IProduct
{
public string Merk { get { return "Melk"; } }
}
Stel nu dat ik logica wil schrijven die lijsten van IProduct sorteert op merk. Ik kan dit als volgt aanpakken.
class Vergelijk : IComparer<IProduct>
{
public int Compare(IProduct x, IProduct y)
{ return x.Merk.CompareTo(y.Merk); }
}
Met de volgende statements zullen de meeste ontwikkelaars geen problemen hebben
List<IProduct> products = new List<IProduct>();
products.Add(new Melk());
products.Sort(new Vergelijk())
De Sort methode van de List<IProduct> class accepteert objecten die het interace IComparer<IProduct> implementeren. De class Vergelijk doet dat ook. “Geen vuiltje aan de lucht”, zou je denken, maar laten we nu eens naar de volgende statements kijken.
List<Melk> products = new List<Melk>();
products.Add(new Melk());
products.Sort(new Vergelijk())
De variabele products is nu van het type List<Melk> in plaats van List<IProduct>. Op zich niet schokkend maar het stukje code compileert nu niet meer omdat de Sort methode nu een object verwacht dat de interface IComparer<Melk> implementeert. Dat doet de class Vergelijk niet. Die implementeert de interface IComparere<IProduct> die een heel ander type is. Het gevolg is nu dat ik een nieuwe class moet definiëren die de interface IComparer<Melk> implementeert, waarmee ik dan de Sort methode kan aanroepen.
Om dit probleem op te lossen is nu Contravariantie ingevoerd. Dit gedrag kan in de code worden aangegeven door het woordje “in” en kan alleen op generieke interfaces en delegates worden toegepast. Microsoft heeft dit in het .NET Framework 4.0 alvast gedaan voor de Interface IComparer<T>. De interface ziet er nu als volgt uit:
interface IComparer<in T>
IComparer is nu variant geworden waardoor het eerdere stukje code nu wel compileert. Deze vorm van variantie noemen we Contravariant.
Terug naar het overzicht met alle artikelen over Taalvernieuwingen in het .NET Framework 4.0