Domanda

La mia domanda come titolo sopra. Ad esempio,

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

ma dopo tutto contiene solo 1 oggetto.

Possiamo avere un metodo come items.Add (item) ?

come il List<T>

È stato utile?

Soluzione

Non puoi, perché IEnumerable < T > non rappresenta necessariamente una raccolta a cui è possibile aggiungere elementi. In realtà, non rappresenta necessariamente una collezione! Ad esempio:

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

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

Quello che puoi fare, tuttavia, è creare un nuovo IEnumerable oggetto (di tipo non specificato) che, quando elencato, fornirà tutti gli elementi di quello vecchio, più alcuni dei tuoi. Si utilizza Enumerable.Concat per questo:

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

Questo non cambierà l'oggetto array (comunque non è possibile inserire elementi negli array). Ma creerà un nuovo oggetto che elencherà tutti gli elementi dell'array e quindi "Foo". Inoltre, quel nuovo oggetto terrà traccia delle modifiche nell'array (ovvero ogni volta che lo enumererai, vedrai i valori correnti degli elementi).

Altri suggerimenti

Il tipo IEnumerable < T > non supporta tali operazioni. Lo scopo dell'interfaccia IEnumerable < T > è consentire a un consumatore di visualizzare il contenuto di una collezione. Non modificare i valori.

Quando esegui operazioni come .ToList (). Add () stai creando un nuovo Elenco < T > e aggiungendo un valore a tale elenco. Non ha alcun collegamento con l'elenco originale.

Quello che puoi fare è usare il metodo Aggiungi estensione per creare un nuovo IEnumerable < T > con il valore aggiunto.

items = items.Add("msg2");

Anche in questo caso non modificherà l'oggetto IEnumerable < T > originale. Questo può essere verificato tenendo un riferimento ad esso. Ad esempio

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

Dopo questo insieme di operazioni, la variabile temp farà ancora riferimento a un enumerabile con un singolo elemento "pippo". nell'insieme di valori mentre gli articoli faranno riferimento a un diverso enumerabile con valori "pippo" e "barra".

Modifica

Dimentico costantemente che Aggiungi non è un tipico metodo di estensione su IEnumerable < T > perché è uno dei primi che alla fine definisco. Eccolo

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

Hai preso in considerazione l'utilizzo di ICollection < T > o IList < T > interfacce invece, esistono proprio per il motivo per cui si desidera avere un metodo Aggiungi su un IEnumerable < T > .

IEnumerable < T > è usato per 'contrassegnare' un tipo come ... beh, enumerabile o solo una sequenza di elementi senza necessariamente fornire garanzie sul fatto che l'oggetto reale sottostante supporti l'aggiunta / rimozione di oggetti. Ricorda inoltre che queste interfacce implementano IEnumerable < T > in modo da ottenere tutti i metodi di estensione che ottieni anche con IEnumerable < T > .

Un paio di metodi di estensione breve e dolce su IEnumerable e IEnumerable < T > fallo per me:

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);
}

Elegante (bene, tranne per le versioni non generiche). Peccato che questi metodi non siano nel BCL.

No, IEnumerable non supporta l'aggiunta di elementi.

La tua 'alternativa' è:

var List = new List(items);
List.Add(otherItem);

In .net Core esiste un metodo Enumerable.Append che fa esattamente questo.

Il codice sorgente del metodo è disponibile su GitHub. .... L'implementazione (più sofisticata dei suggerimenti in altre risposte) merita una visita :).

Per aggiungere un secondo messaggio è necessario -

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

Non solo non è possibile aggiungere elementi come si afferma, ma se si aggiunge un elemento a un Elenco < T > (o praticamente a qualsiasi altra raccolta non di sola lettura) di cui si dispone enumeratore per, l'enumeratore è invalidato (genera InvalidOperationException da quel momento in poi).

Se si stanno aggregando risultati da un tipo di query di dati, è possibile utilizzare il metodo di estensione Concat :

Modifica: inizialmente ho usato l'estensione Union , che non è proprio corretta. La mia applicazione lo utilizza ampiamente per assicurarsi che le query sovrapposte non duplicino i risultati.

IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);

Sono appena venuto qui per dire che, oltre al metodo di estensione Enumerable.Concat , sembra che ci sia un altro metodo chiamato Enumerable.Append in .NET Core 1.1.1 . Quest'ultimo consente di concatenare un singolo elemento in una sequenza esistente. Quindi la risposta di Aamol può anche essere scritta come

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

Tuttavia, tieni presente che questa funzione non cambierà la sequenza di input, ma restituirà semplicemente un wrapper che mette insieme la sequenza data e l'elemento aggiunto.

Altri hanno già dato grandi spiegazioni sul perché non puoi (e non dovresti!) essere in grado di aggiungere elementi a un IEnumerable . Aggiungerò che se stai cercando di continuare a scrivere codice su un'interfaccia che rappresenta una raccolta e desideri un metodo di aggiunta, dovresti codificare ICollection o IList . Come ulteriore aggiunta, queste interfacce implementano IEnumerable .

puoi farlo.

//Create IEnumerable    
IEnumerable<T> items = new T[]{new T("msg")};

//Convert to list.
List<T> list = items.ToList();

//Add new item to list.
list.add(new T("msg2"));

//Cast list to IEnumerable
items = (IEnumerable<T>)items;

Il modo più semplice per farlo è semplicemente

IEnumerable<T> items = new T[]{new T("msg")};
List<string> itemsList = new List<string>();
itemsList.AddRange(items.Select(y => y.ToString()));
itemsList.Add("msg2");

Quindi puoi restituire l'elenco come IEnumerable anche perché implementa l'interfaccia IEnumerable

Certo che puoi (lascio da parte la tua T-business):

public IEnumerable<string> tryAdd(IEnumerable<string> items)
{
    List<string> list = items.ToList();
    string obj = "";
    list.Add(obj);

    return list.Select(i => i);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top