Come posso aggiungere un articolo ad una collezione IEnumerable?

La mia domanda come titolo sopra. Per esempio,

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

ma dopotutto ha solo 1 object dentro.

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

come la List

Non è ansible, perché IEnumerable non rappresenta necessariamente una raccolta a cui è ansible aggiungere elementi. In realtà, non rappresenta necessariamente una collezione! Per esempio:

 IEnumerable ReadLines() { string s; do { s = Console.ReadLine(); yield return s; } while (s != ""); } IEnumerable lines = ReadLines(); lines.Add("foo") // so what is this supposed to do?? 

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

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

Questo non cambierà l’object dell’array (non è ansible inserire oggetti negli array, comunque). Ma creerà un nuovo object che elencherà tutti gli elementi dell’array, e quindi “Foo”. Inoltre, quel nuovo object terrà traccia delle modifiche nell’array (ad esempio, ogni volta che lo enumerate, vedrai i valori attuali degli elementi).

Il tipo IEnumerable non supporta tali operazioni. Lo scopo dell’interfaccia IEnumerable è consentire a un utente di visualizzare i contenuti di una raccolta. Non modificare i valori.

Quando esegui operazioni come .ToList (). Add () stai creando una nuova List e aggiungendo un valore a tale elenco. Non ha alcuna connessione alla lista originale.

Quello che puoi fare è utilizzare il metodo Aggiungi estensione per creare un nuovo IEnumerable con il valore aggiunto.

 items = items.Add("msg2"); 

Anche in questo caso non modificherà l’object IEnumerable originale. Questo può essere verificato tenendo un riferimento ad esso. Per esempio

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

Dopo questo insieme di operazioni, la variabile temp farà ancora riferimento ad una enumerabile con un singolo elemento “pippo” nell’insieme di valori mentre gli oggetti faranno riferimento a una enumerabile differente con i valori “foo” e “bar”.

MODIFICARE

Non dimentico che Add non è un metodo di estensione tipico su IEnumerable perché è uno dei primi che ho definito. Ecco qui

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

Avete preso in considerazione l’utilizzo delle interfacce ICollection o IList , invece esistono proprio per la ragione che volete avere un metodo ‘Aggiungi’ su un object IEnumerable . IEnumerable è usato per ‘contrassegnare’ un tipo come … beh .. enumerabile o solo una sequenza di elementi senza necessariamente garantire se il vero object sottostante supporta l’aggiunta / rimozione di elementi. Ricorda inoltre che queste interfacce implementano IEnumerable in modo da ottenere tutti i metodi di estensioni che ottieni con IEnumerable .

Un paio di brevi, dolci metodi di estensione su IEnumerable e IEnumerable fanno per me:

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

Elegante (beh, ad eccezione delle versioni non generiche). Peccato che questi metodi non siano nel BCL.

No, IEnumerable non supporta l’aggiunta di elementi.

Un ‘alternativa’ che hai è.

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

Per aggiungere un secondo messaggio è necessario –

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

Non solo non puoi aggiungere elementi come tu dichiari, ma se aggiungi un elemento a un List (o praticamente qualsiasi altra raccolta non di sola lettura) per cui hai un enumeratore esistente, l’enumeratore viene invalidato (lancia InvalidOperationException da allora in poi).

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

Modifica: inizialmente ho utilizzato l’estensione Union nell’esempio, che non è proprio corretta. La mia applicazione la utilizza ampiamente per assicurarsi che le query sovrapposte non duplichino i risultati.

 IEnumerable itemsA = ...; IEnumerable itemsB = ...; IEnumerable itemsC = ...; return itemsA.Concat(itemsB).Concat(itemsC); 

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) vale la pena dare un’occhiata :).

Altri hanno già fornito grandi spiegazioni sul perché non puoi (e non dovresti!) Essere in grado di aggiungere elementi a un object IEnumerable . Aggiungerò solo che se stai cercando di continuare la codifica su un’interfaccia che rappresenta una raccolta e vuoi un metodo di aggiunta, devi codificarti su ICollection o IList . Come ulteriore vantaggio, queste interfacce implementano IEnumerable .

Sono venuto qui per dire che, a parte il metodo di estensione Enumerable.Concat , sembra esserci 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 items = new T[]{new T("msg")}; items = items.Append(new T("msg2")); 

Comunque, 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.

Puoi farlo.

 //Create IEnumerable IEnumerable items = new T[]{new T("msg")}; //Convert to list. List list = items.ToList(); //Add new item to list. list.add(new T("msg2")); //Cast list to IEnumerable items = (IEnumerable)items; 

Il modo più semplice per farlo è semplicemente

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

Quindi è ansible restituire l’elenco come IEnumerable anche perché implementa l’interfaccia IEnumerable

Certo, puoi (sto lasciando da parte il tuo T-business):

 public IEnumerable tryAdd(IEnumerable items) { List list = items.ToList(); string obj = ""; list.Add(obj); return list.Select(i => i); }