Es scheint, dass ein List-Objekt nicht in einer List-Variablen in C # gespeichert und nicht einmal explizit auf diese Weise umgewandelt werden kann.
List<string> sl = new List<string>();
List<object> ol;
ol = sl;
Ergebnisse in Can nicht implizit konvertiert Typ System.Collections.Generic.List<string>
zuSystem.Collections.Generic.List<object>
Und dann...
List<string> sl = new List<string>();
List<object> ol;
ol = (List<object>)sl;
Ergebnisse in Typ kann nicht konvertiert werden System.Collections.Generic.List<string>
inSystem.Collections.Generic.List<object>
Natürlich können Sie dies tun, indem Sie alles aus der Zeichenfolgenliste herausziehen und einzeln wieder einfügen, aber es ist eine ziemlich komplizierte Lösung.
c#
.net
generics
covariance
type-safety
Matt Sheppard
quelle
quelle
Antworten:
Stellen Sie sich das so vor: Wenn Sie eine solche Besetzung durchführen und dann ein Objekt vom Typ Foo zur Liste hinzufügen, ist die Liste der Zeichenfolgen nicht mehr konsistent. Wenn Sie die erste Referenz iterieren würden, würden Sie eine Klassenumwandlungsausnahme erhalten, da die Foo nach dem Aufrufen der Foo-Instanz nicht in eine Zeichenfolge konvertiert werden konnte!
Als Randnotiz denke ich, dass es wichtiger wäre, ob Sie die umgekehrte Besetzung machen können oder nicht:
Ich habe C # schon eine Weile nicht mehr verwendet, daher weiß ich nicht, ob das legal ist, aber diese Art der Besetzung ist tatsächlich (möglicherweise) nützlich. In diesem Fall wechseln Sie von einer allgemeineren Klasse (Objekt) zu einer spezifischeren Klasse (Zeichenfolge), die sich von der allgemeinen Klasse erstreckt. Auf diese Weise verletzen Sie nicht die Liste der Objekte, wenn Sie der Liste der Zeichenfolgen hinzufügen.
Weiß jemand oder kann er testen, ob eine solche Besetzung in C # legal ist?
quelle
ol
etwas drin wäre, das kein String ist, würde ich wahrscheinlich erwarten, dass die Besetzung zur Laufzeit fehlschlägt. Aber wo Sie wirklich in Schwierigkeiten geraten würden, wäre, wenn die Besetzung erfolgreich wäre und dann etwas hinzugefügt würdeol
, das keine Zeichenfolge ist. Da Siesl
auf dasselbe Objekt verweisen, enthält Ihr Objekt jetztList<string>
eine Nicht-Zeichenfolge. DasAdd
ist das Problem, das ich denke , rechtfertigt , warum dieser Code wird nicht kompiliert, aber es wird kompilieren , wenn Sie ändernList<object> ol
zuIEnumerable<object> ol
, was nicht hatAdd
. (Ich habe dies in C # 4 überprüft.)InvalidCastException
da der Laufzeit-Typ vonol
immer noch istList<object>
.Wenn Sie .NET 3.5 verwenden, sehen Sie sich die Enumerable.Cast-Methode an. Es ist eine Erweiterungsmethode, mit der Sie sie direkt in der Liste aufrufen können.
Es ist nicht genau das, wonach Sie gefragt haben, aber es sollte den Trick machen.
Bearbeiten: Wie von Zooba bemerkt, können Sie dann ol.ToList () aufrufen, um eine Liste zu erhalten
quelle
Sie können nicht zwischen generischen Typen mit unterschiedlichen Typparametern wechseln. Spezialisierte generische Typen sind nicht Teil desselben Vererbungsbaums und daher auch nicht verwandte Typen.
So führen Sie dies vor NET 3.5 durch:
Verwenden von Linq:
quelle
Der Grund ist, dass eine generische Klasse wie
List<>
für die meisten Zwecke extern als normale Klasse behandelt wird. zB wenn du sagstList<string>()
der Compiler sagtListString()
(was Strings enthält). [Technische Leute: Dies ist eine extrem einfach englischsprachige Version dessen, was los ist]Folglich kann der Compiler offensichtlich nicht intelligent genug sein, um einen ListString in ein ListObject zu konvertieren, indem er die Elemente seiner internen Sammlung umwandelt.
Aus diesem Grund gibt es Erweiterungsmethoden für IEnumerable wie Convert (), mit denen Sie problemlos Konvertierungen für die in einer Sammlung gespeicherten Elemente bereitstellen können. Dies kann so einfach sein wie das Umwandeln von einem zum anderen.
quelle
Dies hat viel mit Kovarianz zu tun, z. B. werden generische Typen als Parameter betrachtet, und wenn die Parameter nicht ordnungsgemäß in einen spezifischeren Typ aufgelöst werden, schlägt die Operation fehl. Dies impliziert, dass Sie wirklich nicht in ein allgemeineres typähnliches Objekt umwandeln können. Und wie von Rex angegeben, konvertiert das List-Objekt nicht jedes Objekt für Sie.
Vielleicht möchten Sie stattdessen den ff-Code ausprobieren:
oder:
ol kopiert (theoretisch) problemlos den gesamten Inhalt von sl.
quelle
Ja, ab .NET 3.5 können Sie:
quelle
Mike - Ich glaube, Kontravarianz ist auch in C # nicht erlaubt
Weitere Informationen finden Sie unter Generische Typparametervarianz in der CLR .
quelle
Ich denke, dass dies (Kontravarianz) tatsächlich in C # 4.0 unterstützt wird. http://blogs.msdn.com/charlie/archive/2008/10/27/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx
quelle
Das ist eigentlich so, dass Sie nicht versuchen, ein seltsames "Objekt" in Ihre "alte" Listenvariante einzufügen (wie
List<object>
es zu erlauben scheint) - weil Ihr Code dann abstürzen würde (weil die Liste wirklich ist)List<string>
Objekte vom Typ String und nur Objekte vom Typ String akzeptiert ). Aus diesem Grund können Sie Ihre Variable nicht in eine allgemeinere Spezifikation umwandeln.Unter Java ist es umgekehrt, Sie haben keine Generika und stattdessen ist alles zur Laufzeit eine Objektliste, und Sie können wirklich jedes seltsame Objekt in Ihre angeblich streng typisierte Liste einfügen. Suchen Sie nach "Reified Generics", um eine breitere Diskussion über das Problem von Java zu erhalten ...
quelle
Eine solche Kovarianz bei Generika wird nicht unterstützt, aber Sie können dies tatsächlich mit Arrays tun:
C # führt Laufzeitprüfungen durch, um zu verhindern, dass Sie beispielsweise ein
int
in setzena
.quelle
Hier ist eine weitere Pre-.NET 3.5-Lösung für jeden IList, dessen Inhalt implizit umgewandelt werden kann.
(Basierend auf Zoobas Beispiel)
quelle
Ich habe ein:
Und ich wollte es mit Daten füllen, die in einem gesammelt wurden.
List<object>
Was für mich schließlich funktionierte, war dieses:.Cast
es auf die Art wollen Sie eine bekommenIEnumerable
von dieser Art, dann die TypumwandlungIEnemuerable
auf dieList<>
Sie wollen.quelle
Mm, dank vorheriger Kommentare habe ich zwei Möglichkeiten gefunden, es herauszufinden. Der erste besteht darin, die Zeichenfolgenliste der Elemente abzurufen und sie dann in die IEnumerable-Objektliste umzuwandeln:
Und die zweite besteht darin, den IEnumerable-Objekttyp zu vermeiden, einfach die Zeichenfolge in den Objekttyp umzuwandeln und dann die Funktion "toList ()" im selben Satz zu verwenden:
Ich mag mehr den zweiten Weg. Ich hoffe das hilft.
quelle
quelle