Generics Typ Gießen

8

Ich bekomme einfach nichts im generischen .NET-Casting. Kann jemand erklären, was im folgenden Codefragment passiert?

%Vor%     
Vasaka 11.09.2012, 17:55
quelle

3 Antworten

11

Beginnen wir mit der zweiten Zeile, die am einfachsten ist.

Diese Umwandlung funktioniert, weil der Typparameter von IEnumerable<T> jetzt kovariante (das ist die out in out T ). Das bedeutet, dass Sie IEnumerable<Derived> in ein IEnumerable<Base> frei umwandeln können.

Die erste Zeile, die scheinbar der gleiche Fall ist, funktioniert nicht, weil int ein Werttyp ist. Die Schnittstellenvarianz funktioniert überhaupt nicht mit Werttypen, da Werttypen nicht wirklich von System.Object ; Sie können in ein object eingerahmt werden, aber das ist nicht das Gleiche. Die Dokumentation erwähnt das

  

Varianz gilt nur für Referenztypen; wenn Sie einen Werttyp angeben   Für einen variant type -Parameter ist dieser type-Parameter invariant für   resultierender konstruierter Typ.

Schließlich funktioniert die dritte Zeile nicht, weil der Typparameter von List<T> ist invariant . Sie können sehen, dass es keinen out auf seinem Typparameter gibt; Die Regeln verbieten das, weil List<T> keine Schnittstelle ist:

  

In .NET Framework 4 sind die Parameter des Varianttyps beschränkt auf   generische Schnittstelle und generische Delegattypen.

    
Jon 11.09.2012, 18:00
quelle
2

Dies liegt daran, dass die Schnittstellen-Kovarianz nur mit Referenztypen funktioniert. Int32 ist natürlich ein Werttyp.

Hier finden Sie weitere Informationen: Ссылка

Und das tut es auch: Ссылка

    
phoog 11.09.2012 17:59
quelle
0

Die Definition jedes Typs, der von System.ValueType abgeleitet wird, mit Ausnahme von System.Enum , definiert tatsächlich zwei Arten von Dingen: einen Heap-Objekttyp und einen Speicherorttyp. Instanzen der letzteren können implizit in die erstere konvertiert werden (indem eine Kopie der darin enthaltenen Daten erstellt wird), und Instanzen der ersteren können explizit auf letztere typisiert werden (ebenfalls); obwohl beide Arten von Dingen durch die gleiche System.Type beschrieben werden, und obwohl sie die gleichen Mitglieder haben, verhalten sie sich sehr unterschiedlich.

A List<AnyClassType> erwartet eine Menge von Heap-Objektreferenzen; Ob die fragliche Liste ein List<String> , List<StringBuilder> , List<Button> oder was auch immer ist, mag für die Benutzer der Liste von Interesse sein, ist aber nicht wirklich von Interesse für List<T> selbst. Wenn man ein List<Button> auf ein IEnumerable<Control> umsetzt, erwartet jemand, der seine GetEnumerator() -Methode aufruft, ein Objekt, das Referenzen auf Heap-Objekte ausgibt, die von Control ; Die Rückkehr von List<Button>.GetEnumerator() wird diese Erwartung erfüllen. Im Gegensatz dazu würde jemand, der List<Int32> auf List<Object> umsetzt, jemanden erwarten, der GetEnumerator() aufruft, würde aber etwas erwarten, das Heap-Objektreferenzen ausgeben würde, aber List<Integer>.GetEnumerator liefert stattdessen etwas, das Ganzzahlen vom Werttyp ausgibt.

Es ist möglich, Int32 Werte in einem List<Object> oder einem List<ValueType> zu speichern; Wenn Sie eine ganze Zahl in eine solche Liste speichern, wird sie in ihr Heap-Objekt konvertiert und ein Verweis darauf gespeichert. Der Aufruf von GetEnumerator() würde etwas ergeben, das Heap-Referenzen ausgibt. Es gibt jedoch keine Möglichkeit anzugeben, dass eine solche Liste nur Instanzen des Heap-Typs enthält, der Int32 entspricht. In C ++ / CLI ist es möglich, Variablen vom Typ "Verweis auf Heap-gespeicherten Werttyp" zu deklarieren, aber die Mechanismen hinter generischen Typen in .net können nicht mit solchen Typen arbeiten.

    
supercat 21.01.2013 18:41
quelle

Tags und Links