505 Stimmen

Wie kann ich ein Element zu einer IEnumerable<T>-Sammlung hinzufügen?

Meine Frage als Titel oben. Zum Beispiel

IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));

aber es ist ja nur 1 Gegenstand drin. Können wir eine Methode haben wie items.Add(item) wie die List<T> ?

574voto

Pavel Minaev Punkte 97251

Das können Sie nicht, denn IEnumerable<T> stellt nicht unbedingt eine Sammlung dar, der Elemente hinzugefügt werden können. Tatsächlich stellt sie nicht unbedingt eine Sammlung dar! Zum Beispiel:

IEnumerable<string> ReadLines()
{
     string s;
     do
     {
          s = Console.ReadLine();
          yield return s;
     } while (!string.IsNullOrEmpty(s));
}

IEnumerable<string> lines = ReadLines();
lines.Add("foo") // so what is this supposed to do??

Was Sie jedoch tun können, ist die Erstellung einer neu IEnumerable Objekt (von nicht spezifiziertem Typ), das, wenn es aufgezählt wird, alle Elemente des alten Objekts sowie einige Ihrer eigenen Elemente enthält. Sie verwenden Enumerable.Concat dafür:

 items = items.Concat(new[] { "foo" });

Diese wird das Array-Objekt nicht verändern (Sie können ohnehin keine Elemente in to-Arrays einfügen). Aber es wird ein neues Objekt erstellt, das alle Elemente im Array auflistet, und dann "Foo". Außerdem wird dieses neue Objekt Verfolgung von Änderungen im Array (d.h. immer wenn Sie es aufzählen, werden Sie die aktuellen Werte der Elemente sehen).

125voto

JaredPar Punkte 699699

Der Typ IEnumerable<T> unterstützt solche Operationen nicht. Der Zweck der IEnumerable<T> Schnittstelle ist es, einem Verbraucher die Möglichkeit zu geben, den Inhalt einer Sammlung einzusehen. Nicht um die Werte zu ändern.

Wenn Sie Operationen wie .ToList().Add() durchführen, erstellen Sie eine neue List<T> und einen Wert zu dieser Liste hinzufügen. Sie hat keine Verbindung zur ursprünglichen Liste.

Sie können die Erweiterungsmethode Add verwenden, um eine neue IEnumerable<T> mit dem Zusatznutzen.

items = items.Add("msg2");

Auch in diesem Fall wird das Original nicht verändert. IEnumerable<T> Objekt. Dies kann durch einen Verweis auf das Objekt überprüft werden. Zum Beispiel

var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");

Nach dieser Reihe von Operationen verweist die Variable temp weiterhin nur auf eine Aufzählung mit einem einzigen Element "foo" in der Wertemenge, während items auf eine andere Aufzählung mit den Werten "foo" und "bar" verweist.

EDIT

Ich vergesse immer wieder, dass Add keine typische Erweiterungsmethode für IEnumerable<T> weil es eine der ersten ist, die ich definiere. Hier ist sie

public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
  foreach ( var cur in e) {
    yield return cur;
  }
  yield return value;
}

78voto

Abhijeet Patel Punkte 6184

Haben Sie die Verwendung von ICollection<T> o IList<T> stattdessen existieren sie genau aus dem Grund, dass man eine Add Methode auf eine IEnumerable<T> .

IEnumerable<T> wird verwendet, um einen Typ als... nun ja, aufzählbar oder einfach als eine Folge von Elementen zu "markieren", ohne notwendigerweise irgendwelche Garantien dafür zu geben, ob das tatsächliche zugrunde liegende Objekt das Hinzufügen/Entfernen von Elementen unterstützt. Denken Sie auch daran, dass diese Schnittstellen Folgendes implementieren IEnumerable<T> Sie erhalten also alle Erweiterungsmethoden, die Sie mit IEnumerable<T> auch.

75voto

JanDotNet Punkte 3306

In .net Core gibt es eine Methode Enumerable.Append die genau das tut.

Der Quellcode der Methode lautet verfügbar auf GitHub. .... Die Implementierung (anspruchsvoller als die Vorschläge in anderen Antworten) ist einen Blick wert :).

37voto

Ein paar kurze, süße Erweiterungsmethoden auf IEnumerable y IEnumerable<T> tun Sie es für mich:

public static IEnumerable Append(this IEnumerable first, params object[] second)
{
    return first.OfType<object>().Concat(second);
}
public static IEnumerable<T> Append<T>(this IEnumerable<T> first, params T[] second)
{
    return first.Concat(second);
}   
public static IEnumerable Prepend(this IEnumerable first, params object[] second)
{
    return second.Concat(first.OfType<object>());
}
public static IEnumerable<T> Prepend<T>(this IEnumerable<T> first, params T[] second)
{
    return second.Concat(first);
}

Elegant (außer bei den nicht-generischen Versionen). Schade, dass diese Methoden nicht in der BCL sind.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X