Ich weiß, dass es möglich ist, eine Liste von Elementen von einem Typ in einen anderen umzuwandeln (vorausgesetzt, Ihr Objekt verfügt über eine öffentliche statische explizite Operatormethode, um das Umwandeln durchzuführen), und zwar wie folgt:
List<Y> ListOfY = new List<Y>();
foreach(X x in ListOfX)
ListOfY.Add((Y)x);
Aber ist es nicht möglich, die gesamte Liste auf einmal zu besetzen? Beispielsweise,
ListOfY = (List<Y>)ListOfX;
c#
list
casting
ienumerable
Jimbo
quelle
quelle
Antworten:
Wenn
X
wirklich gegossen werdenY
kann, sollten Sie in der Lage sein, zu verwendenEinige Dinge zu beachten (H / T an Kommentatoren!)
using System.Linq;
, um diese Erweiterungsmethode zu erhaltenList<Y>
Durch den Aufruf von wird ein neues erstelltToList()
.quelle
Cast<T>
Methode keine benutzerdefinierten Konvertierungsoperatoren unterstützt. Warum funktioniert die Linq Guss Helper keine Arbeit mit dem impliziten Cast Operator .Die direkte Besetzung
var ListOfY = (List<Y>)ListOfX
ist nicht möglich, da dies eine Co / Contravarianz desList<T>
Typs erfordern würde , und dies kann einfach nicht in jedem Fall garantiert werden. Bitte lesen Sie weiter, um die Lösungen für dieses Casting-Problem zu sehen.Während es normal erscheint, Code wie folgt schreiben zu können:
Da wir garantieren können, dass jedes Säugetier ein Tier ist, ist dies offensichtlich ein Fehler:
da nicht jedes Tier ein Säugetier ist.
Mit C # 3 und höher können Sie jedoch verwenden
das erleichtert das Casting ein wenig. Dies entspricht syntaktisch Ihrem nacheinander hinzugefügten Code, da er eine explizite Umwandlung verwendet, um jede
Mammal
in der Liste in eineAnimal
umzuwandeln, und schlägt fehl, wenn die Umwandlung nicht erfolgreich ist.Wenn Sie mehr Kontrolle über den Casting- / Konvertierungsprozess wünschen, können Sie die
ConvertAll
Methode derList<T>
Klasse verwenden, die einen angegebenen Ausdruck zum Konvertieren der Elemente verwenden kann. Es hat den zusätzlichen Vorteil, dass es aList
anstelle von zurückgibtIEnumerable
, sodass kein.ToList()
erforderlich ist.quelle
Um zu Swekos Punkt hinzuzufügen:
Der Grund warum die Besetzung
ist nicht möglich, weil das im Typ T invariant
List<T>
ist und es daher keine Rolle spielt, ob es von ) stammt - dies liegt daran, dass definiert ist als:X
Y
List<T>
(Beachten Sie, dass in dieser Deklaration der Typ
T
hier keine zusätzlichen Varianzmodifikatoren enthält.)Wenn jedoch wandelbar Sammlungen sind nicht in Ihrem Design erforderlich, eine upcast auf vielen der unveränderlichen Sammlungen, ist möglich , zum Beispiel vorgesehen , dass
Giraffe
ergibt sich ausAnimal
:Dies liegt daran, dass
IEnumerable<T>
die Kovarianz in unterstützt wird.T
Dies ist sinnvoll,IEnumerable
da die Auflistung nicht geändert werden kann, da Methoden zum Hinzufügen oder Entfernen von Elementen zur Auflistung nicht unterstützt werden. Beachten Sie dasout
Schlüsselwort in der Deklaration vonIEnumerable<T>
:( Hier ist eine weitere Erklärung für den Grund, warum veränderbare Sammlungen wie
List
nicht unterstützt werden könnencovariance
, während unveränderliche Iteratoren und Sammlungen dies können.)Casting mit
.Cast<T>()
Wie andere bereits erwähnt haben,
.Cast<T>()
kann es auf eine Sammlung angewendet werden, um eine neue Sammlung von Elementen zu projizieren, die in T umgewandelt wurden. Dies führt jedoch zu einem,InvalidCastException
wenn die Umwandlung in ein oder mehrere Elemente nicht möglich ist (was das gleiche Verhalten wie beim expliziten Ausführen wäre in dieforeach
Schleife des OP geworfen ).Filtern und Gießen mit
OfType<T>()
Wenn die Eingabeliste Elemente unterschiedlicher, inkompatibler Typen enthält, kann das Potenzial
InvalidCastException
durch Verwendung von.OfType<T>()
anstelle von vermieden werden.Cast<T>()
. (.OfType<>()
Überprüft vor dem Versuch der Konvertierung, ob ein Element in den Zieltyp konvertiert werden kann, und filtert inkompatible Typen heraus.)für jedes
Beachten Sie auch, dass, wenn das OP dies stattdessen geschrieben hätte: (beachten Sie das explizite
Y y
in derforeach
)dass das Casting auch versucht wird. Wenn jedoch keine Besetzung möglich ist,
InvalidCastException
ergibt sich ein Wille.Beispiele
Zum Beispiel angesichts der einfachen (C # 6) Klassenhierarchie:
Bei der Arbeit mit einer Sammlung gemischter Typen:
Wohingegen:
filtert nur die Elefanten heraus - dh Zebras werden eliminiert.
Betreff: Implizite Cast-Operatoren
Ohne dynamische, benutzerdefinierte Konvertierungsoperatoren werden nur zur Kompilierungszeit * verwendet. Selbst wenn ein Konvertierungsoperator zwischen beispielsweise Zebra und Elephant verfügbar wäre, würde sich das obige Laufzeitverhalten der Konvertierungsansätze nicht ändern.
Wenn wir einen Konvertierungsoperator hinzufügen, um ein Zebra in einen Elefanten zu konvertieren:
Stattdessen angesichts der obigen Umwandlungsoperator, wird der Compiler in der Lage sein , den Typ des nachfolgend Array ändern aus
Animal[]
zuElephant[]
bestimmten, dass die Zebras kann nun zu einer homogenen Ansammlung von Elefanten umgewandelt werden:Verwenden impliziter Konvertierungsoperatoren zur Laufzeit
* Wie von Eric erwähnt, kann auf den Konvertierungsoperator jedoch zur Laufzeit zugegriffen werden, indem auf Folgendes zurückgegriffen wird
dynamic
:quelle
foreach
filtert nicht, aber die Verwendung eines stärker abgeleiteten Typs als Iterationsvariable zwingt den Compiler dazu, einen Cast zu versuchen, der für das erste Element fehlschlägt, das nicht den Anforderungen entspricht.Sie können verwenden
List<Y>.ConvertAll<T>([Converter from Y to T]);
quelle
Dies ist nicht ganz die Antwort auf diese Frage, aber es kann für einige nützlich sein: Wie @SWeko sagte, kann dank Kovarianz und Kontravarianz
List<X>
nicht eingegossen werdenList<Y>
, sondernList<X>
kann hineingegossen werdenIEnumerable<Y>
, und sogar mit impliziter Besetzung.Beispiel:
aber
Der große Vorteil ist, dass keine neue Liste im Speicher erstellt wird.
quelle
quelle