Frage

Allg Varianz in C # 4.0 ist so implementiert, dass es möglich die folgend ohne Ausnahme zu schreiben (was in C # passieren würde, 3.0):

 List<int> intList = new List<int>();
 List<object> objectList = intList; 

[Beispiel nicht-funktional: Siehe Jon Skeet Antwort]

Ich habe kürzlich an einer Konferenz, wo Jon Skeet einen hervorragenden Überblick über Allgemein Variance gab, aber ich bin nicht sicher, ob ich es vollständig erhalten - ich die Bedeutung des in verstehen und Schlüsselwörter out, wenn es um contra und Co kommt -variance, aber ich bin gespannt, was hinter den Kulissen passiert.

Was sieht der CLR, wenn dieser Code ausgeführt wird? Ist es implizit die List<int> Umwandlung zu List<object> oder ist es einfach, dass bauten wir zwischen abgeleiteten Typen zu übergeordneten Typen jetzt umwandeln kann?

Aus Interesse, warum dies in früheren Versionen eingeführt wurde, nicht und was ist der Hauptvorteil - also reale Welt Nutzung

Weitere Informationen über diese Post für Generic Variance (aber Frage ist extrem veraltet, für echt wirkende, up-to-date Informationen)

War es hilfreich?

Lösung

Nein, würde Ihr Beispiel aus drei Gründen nicht funktionieren:

  • Klassen (wie List<T>) sind unveränderlich; nur Delegierte und Schnittstellen sind Variante
  • Für Varianz zu arbeiten, wobei die Schnittstelle nur hat, um die Typ-Parameter in eine Richtung verwendet werden (in für Kontra, heraus für Kovarianz)
  • Werttypen werden nicht als Typargument für Varianz unterstützt - so gab es keine Umrechnungen von IEnumerable<int> zum Beispiel IEnumerable<object>

(Der Code nicht in C # 3.0 und 4.0 kompilieren -. Es gibt keine Ausnahme)

Also die würde Arbeit:

IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;

Die CLR verwendet nur die Referenz unverändert - keine neuen Objekte erzeugt werden. Also, wenn Sie objects.GetType() genannt Sie noch List<string> bekommen würde.

Ich glaube, es nicht früher eingeführt wurde, weil die Sprachdesigner noch die Details auszuarbeiten hatten, wie man es aussetzen -. Es ist seit v2 in der CLR gewesen

Die Vorteile sind die gleichen wie andere Zeiten, in denen Sie in der Lage sein wollen, eine Art als eine andere zu verwenden. Um das gleiche Beispiel verwende ich am vergangenen Samstag verwendet, wenn Sie etwas implementiert haben IComparer<Shape> Formen zu vergleichen Bereich, es ist verrückt, dass Sie nicht, dass eine List<Circle> sortieren können - wenn es keine zwei Formen vergleichen kann, kann es auf jeden Fall vergleichen alle zwei Kreise. Wie von C # 4, eine kontra Umwandlung von IComparer<Shape> würde IComparer<Circle> so könnte man circles.Sort(areaComparer) nennen.

Andere Tipps

Ein paar zusätzliche Gedanken.

  

Was bedeutet die CLR sehen, wenn dieser Code ausgeführt wird,

Wie Jon und andere haben richtig bemerkt, werden wir tun Varianz auf Klassen nicht nur Schnittstellen und Delegierten. Also in Ihrem Beispiel sieht die CLR nichts; dieser Code nicht kompiliert. Wenn Sie es durch das Einfügen genug Würfe zu kompilieren zwingen, sie zur Laufzeit mit einer schlechten Guss Ausnahme abstürzt.

Nun, es ist immer noch eine vernünftige Frage zu fragen, wie Varianz hinter den Kulissen funktioniert, wenn es funktioniert. Die Antwort lautet: der Grund, warum wir schränken diese Art Argumente zu verweisen, die Schnittstelle und Delegattypen parametrieren ist so, dass nichts hinter den Kulissen passiert. Wenn Sie sagen,

object x = "hello";

, was hinter den Kulissen passiert, ist die Referenz auf den String in die Variable vom Typ Objekt geklebt wird ohne Änderungen . Die Bits, die einen Verweis auf eine Zeichenfolge bilden, sind rechtliche Bits zu einem Objekt eine Referenz zu sein, also nichts muss hier geschehen. Die CLR einfach stoppt Denken dieses Bits als Bezugnahme auf einen String und beginnt von ihnen denkt, wie mit Bezug auf ein Objekt.

Wenn Sie sagen:

IEnumerator<string> e1 = whatever;
IEnumerator<object> e2 = e1;

Die gleiche Sache. Nichts passiert. Die Bits, die eine Referenz auf einen String-Enumerator machen, sind die gleichen wie die Bits, die einen Verweis auf ein Objekt Enumerator machen. Es gibt etwas mehr Magie, die ins Spiel kommt, wenn Sie eine Besetzung zu tun, sagen:

IEnumerator<string> e1 = whatever;
IEnumerator<object> e2 = (IEnumerator<object>)(object)e1;

Jetzt muss die CLR einen Scheck erzeugen, die tatsächlich e1 diese Schnittstelle nicht implementiert, und dass der Check hat, schlau sein Varianz zu erkennen.

Aber der Grund, warum wir weg mit Variante bekommen Schnittstellen sind nur No-op Konvertierungen weil regelmäßige Zuordnung Kompatibilität ist auf diese Weise. Was werden Sie e2 benutzen?

object z = e2.Current;

Das Bits zurückgibt, die einen Verweis auf eine Zeichenfolge sind. Wir haben bereits festgestellt, dass diejenigen ohne Änderung mit dem Objekt kompatibel sind.

Warum wurde das nicht früher eingeführt? Wir hatten andere Merkmale und ein begrenztes Budget zu tun.

Was ist das Prinzip Nutzen? Das Umtausch- Folge von String in Folge von Objekt „einfach funktionieren“.

  

Aus Interesse, warum war das nicht   in früheren Versionen eingeführt

Die ersten Versionen (1.x) von .NET nicht hatten überhaupt Generika, so generische Varianz weit weg war.

Es sollte in allen Versionen von .NET zu beachten, gibt Matrixkovarianz ist. Leider ist es nicht sicher Kovarianz:

Apple[] apples = new [] { apple1, apple2 };
Fruit[] fruit = apples;
fruit[1] = new Orange(); // Oh snap! Runtime exception! Can't store an orange in an array of apples!

Die Ko- und Kontravarianz in C # 4 ist sicher, und verhindert, dass dieses Problem.

  

Was ist der Hauptvorteil - also echte   Welt Nutzung?

Viele Male im Code, die Sie anrufen, eine API eine verstärkte Art von Basis erwartet (z IEnumerable<Base>), aber alles, was Sie haben, ist eine verstärkte Aktivität von Abgeleitete (z IEnumerable<Derived>).

In C # 2 und C # 3, dann würden Sie müssen manuell IEnumerable<Base> konvertieren, obwohl es sollte „einfach funktionieren“. Co- und Kontravarianz macht es „einfach funktionieren“.

P. S. Völlig saugt, dass Skeet Antwort isst alle meine rep Punkte. Verdammt Sie, Skeet! :-) Sieht aus wie er ist obwohl beantwortet diese vor .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top