Warum kann in C # kein List <string> -Objekt in einer List <object> -Variable gespeichert werden

  • Es scheint, dass ein List-Objekt nicht in einer List-Variablen in C # gespeichert werden kann und nicht einmal explizit auf diese Weise umgewandelt werden kann.

     [pre> List<string> sl = new List<string>();
    List<object> ol;
    ol = sl;
     

    führt dazu, dass der Typ System.Collections.Generic.List<string> nicht implizit in System.Collections.Generic.List<object>

    konvertiert werden kann und dann ...

     List<string> sl = new List<string>();
    List<object> ol;
    ol = (List<object>)sl;
     

    führt dazu, dass der Typ System.Collections.Generic.List<string> nicht in System.Collections.Generic.List<object>

    konvertiert werden kann Natürlich können Sie dies tun, indem Sie alles aus der Stringliste ziehen und wieder einzeln einfügen, aber es ist eine ziemlich komplizierte Lösung.

    27 September 2012
    useruser1475694
14 answers
  • Stellen Sie sich das so vor: Wenn Sie eine solche Umwandlung 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 Ausnahmebedingung für die Klassenumwandlung erhalten, da die Foo nach dem Anklicken der Foo-Instanz nicht in eine Zeichenfolge konvertiert werden konnte Ich denke, es wäre bedeutender, ob Sie die umgekehrte Umwandlung durchführen können oder nicht:

     List<object> ol = new List<object>();
    List<string> sl;
    sl = (List<string>)ol;
     

    I port ' Ich habe in einiger Zeit C # verwendet, also weiß ich nicht, ob das legal ist, aber diese Art von Cast ist tatsächlich (potentiell) nützlich. In diesem Fall wechseln Sie von einer allgemeineren Klasse (Objekt) zu einer spezifischeren Klasse (Zeichenfolge), die sich von der allgemeinen Klasse erstreckt. Wenn Sie der Liste der Zeichenfolgen hinzufügen, verstoßen Sie auf diese Weise nicht gegen die Liste der Objekte.

    Weiß jemand, ob ein solcher Cast in C # zulässig ist, oder kann er testen?

    09 August 2008
    Mike Stone
  • Wenn Sie .NET 3.5 verwenden, werfen Sie einen Blick auf die Enumerable.Cast-Methode. Es ist eine Erweiterungsmethode, sodass Sie sie direkt in der Liste aufrufen können.

     List<string> sl = new List<string>();
    IEnumerable<object> ol;
    ol = sl.Cast<object>();
     

    Es ist nicht genau das, wonach Sie gefragt haben Sie sollten jedoch den Trick ausführen.

    Bearbeiten: Wie von Zooba angemerkt, können Sie dann ol.ToList () aufrufen, um eine Liste

    zu erhalten
    11 August 2008
    Ray
  • Sie können nicht zwischen generischen Typen mit anderen Typparametern umwandeln. Spezialisierte generische Typen sind nicht Teil des gleichen Vererbungsbaums und daher auch nicht verwandte Typen.

    Um dies vor NET 3.5 zu tun:

     List<string> sl = new List<string>();
    // Add strings to sl
    
    List<object> ol = new List<object>();
    
    foreach(string s in sl)
    {
        ol.Add((object)s);  // The cast is performed implicitly even if omitted
    }
     

    Verwenden von Linq:

     var sl = new List<string>();
    // Add strings to sl
    
    var ol = new List<object>(sl.Cast<object>());
    
    // OR
    var ol = sl.Cast<object>().ToList();
    
    // OR (note that the cast to object here is required)
    var ol = sl.Select(s => (object)s).ToList();
     
    14 August 2008
    Zooba
  • Der Grund ist, dass eine generische Klasse wie List<> für die meisten Zwecke extern als normale Klasse behandelt wird. z.B. Wenn Sie List<string>() sagen, sagt der Compiler ListString() (die Strings enthält). [Technical Folk: Dies ist eine extrem einfache englische Version des aktuellen Inhalts]

    Folglich kann der Compiler offensichtlich nicht intelligent genug sein, um einen ListString in ein ListObject zu konvertieren durch Casting der Elemente der internen Sammlung.

    Deshalb gibt es für IEnumerable Erweiterungsmethoden wie Convert (), mit denen Sie die Konvertierung für die in einer Sammlung gespeicherten Elemente problemlos bereitstellen können Seien Sie so einfach wie das Casting von einem zum anderen.

    09 August 2008
    Rex MFrank Schwieterman
  • Dies hat viel mit Kovarianz zu tun, beispielsweise werden generische Typen als Parameter betrachtet. Wenn die Parameter nicht ordnungsgemäß in einen spezifischeren Typ aufgelöst werden, schlägt die Operation fehl. Dies impliziert, dass Sie nicht in einen allgemeineren Typ wie Objekt umwandeln können. Wie von Rex angegeben, konvertiert das List-Objekt nicht jedes Objekt für Sie.

    Möglicherweise möchten Sie stattdessen den ff-Code verwenden:

     List<string> sl = new List<string>();
    //populate sl
    List<object> ol = new List<object>(sl);
     

    oder:

     List<object> ol = new List<object>();
    ol.AddRange(sl);
     

    ol kopiert (theoretisch) den gesamten Inhalt von sl ohne Probleme.

    09 August 2008
    Jon Limjap
  • Ja, Sie können ab .NET 3.5:

     List<string> sl = new List<string>();
    List<object> ol = sl.Cast<object>().ToList();
     
    19 October 2008
    Tamas Czinege
  • Mike - Ich glaube, dass in C # keine Kontravarianz zulässig ist.

    Siehe Generische Typparameterabweichung in der CLR für weitere Informationen.

    27 January 2013
    Matt Sheppard
  • Ich denke, dass dies in C # 4.0 tatsächlich unterstützt wird.

07 November 2008
MattValerio
  • Das ist eigentlich so, dass Sie nicht versuchen, ein ungerades "Objekt" in Ihre "ol" -Listenvariante einzufügen (wie es List<object> zuzulassen scheint) - weil Ihr Code dann abstürzen würde (weil die Liste ist wirklich List<string> und akzeptiert nur String-Objekte). Aus diesem Grund können Sie Ihre Variable nicht in eine allgemeinere Spezifikation umwandeln.

    Auf Java ist es umgekehrt, Sie haben keine Generics und stattdessen ist alles Objektliste zur Laufzeit, und Sie können wirklich jedes seltsame Objekt in Ihre angeblich streng typisierte Liste einfügen. Suchen Sie nach "Reified Generics", um eine umfassendere Diskussion des Problems von Java zu erhalten ...

    10 August 2008
    Gilles
  • Eine solche Kovarianz bei Generics wird nicht unterstützt, tatsächlich können Sie dies jedoch mit Arrays tun:

     object[] a = new string[] {"spam", "eggs"};
     

    C # führt Laufzeitüberprüfungen durch, um zu verhindern, dass Sie beispielsweise int in a setzen.

    10 October 2008
    Constantin