Jak Mogę dodać przedmiot do kolekcji IEnumerable?

Moje pytanie jak tytuł wyżej. Na przykład,

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

Ale w końcu ma tylko 1 przedmiot w środku.

Czy możemy mieć metodę taką jak items.Add(item)?

Jak List<T>

Author: Abel, 2009-07-31

13 answers

Nie możesz, ponieważ IEnumerable<T> niekoniecznie reprezentuje kolekcję, do której można dodawać elementy. W rzeczywistości wcale nie musi reprezentować kolekcji! Na przykład:

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??

Możesz jednak stworzyć Nowy IEnumerable obiekt (nieokreślonego typu), który po wyliczeniu dostarczy wszystkie elementy starego, plus niektóre własne. Używasz Enumerable.Concat do tego:

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

To nie zmieni obiektu array (nie można wstawiać elementów do tablice, zresztą). Ale utworzy nowy obiekt, który wyświetli wszystkie elementy w tablicy, a następnie "Foo". Co więcej, ten nowy obiekt będzie śledził zmiany w tablicy (tzn. gdy ją wyliczysz, zobaczysz bieżące wartości pozycji).

 391
Author: Pavel Minaev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-12 21:04:06

Typ IEnumerable<T> nie obsługuje takich operacji. Celem interfejsu IEnumerable<T> jest umożliwienie konsumentowi przeglądania zawartości kolekcji. Nie modyfikować wartości.

Kiedy robisz operacje jak .ToList().Add() tworzysz nową List<T> i dodajesz wartość do tej listy. Nie ma połączenia z oryginalną listą.

Możesz użyć metody Add extension, aby utworzyć nową IEnumerable<T> z wartością dodaną.

items = items.Add("msg2");

Nawet w tym przypadku nie będzie zmodyfikuj oryginalny obiekt IEnumerable<T>. Można to sprawdzić, trzymając odniesienie do niego. Na przykład

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

Po Tym Zestawie operacji zmienna temp nadal będzie odwoływać się tylko do wyliczenia z pojedynczym elementem " foo "w zestawie wartości, podczas gdy pozycje będą odwoływać się do innego wyliczenia z wartościami" foo "i"bar".

EDIT

Zapominam, że Add nie jest typową metodą rozszerzenia na IEnumerable<T>, ponieważ jest jedną z pierwszych, które kończę definiowanie. Tutaj jest

public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
  foreach ( var cur in e) {
    yield return cur;
  }
  yield return value;
}
 76
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-31 02:05:56

Czy rozważałeś użycie ICollection lub IList interfejsów zamiast tego, istnieją one z tego powodu, że chcesz mieć metodę 'Add' na liczbach. IEnumerable jest używany do 'oznaczania' typu jako będącego ...cóż.. enumerable lub po prostu Sekwencja elementów bez konieczności podejmowania jakichkolwiek gwarancji, czy rzeczywisty obiekt bazowy obsługuje dodawanie / usuwanie elementów. Pamiętaj również, że te interfejsy implementują IEnumerable, więc otrzymasz wszystkie rozszerzenia metody, które można uzyskać z IEnumerable, jak również.

 45
Author: Abhijeet Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-27 16:06:55

Kilka krótkich, słodkich metod przedłużania na IEnumerable i IEnumerable<T> Zrób to dla mnie:

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

Elegancki (no, z wyjątkiem wersji nie-generycznych). Szkoda, że tych metod nie ma w BCL.

 28
Author: Will,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-23 16:40:09

No Theenumerable doens not support adding items to items.

"alternatywą", którą masz, jest.

var List = new List(items);
List.Add(otherItem);
 13
Author: Paul van Brenk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-31 02:41:28

Aby dodać drugą wiadomość musisz -

IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})
 10
Author: Aamol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-17 03:05:34

Nie tylko nie możesz dodawać elementów takich jak stan, ale jeśli dodasz element do List<T> (lub prawie każdej innej kolekcji nie tylko do odczytu), dla której masz istniejący licznik, licznik jest unieważniany (od tego momentu rzuca InvalidOperationException).

Jeśli agregujesz wyniki z jakiegoś typu zapytania o dane, możesz użyć metody rozszerzenia Concat:

Edit: pierwotnie użyłem rozszerzenia Union w przykładzie, które nie jest do końca poprawne. Moja aplikacja używa go szeroko, aby na pewno nakładające się zapytania nie powielają wyników.

IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);
 8
Author: Sam Harwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-31 02:00:27

W. Net Core istnieje metoda Enumerable.Append, która dokładnie to robi.

Kod źródłowy metody jest dostępny na Githubie..... Warto zajrzeć do realizacji (bardziej wyrafinowanej niż sugestie w innych odpowiedziach):).

 6
Author: JanDotNet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-12 19:34:04

Inni już dali świetne wyjaśnienia, dlaczego nie możesz (i nie powinieneś!) możliwość dodawania elementów do IEnumerable. Dodam tylko, że jeśli chcesz kontynuować kodowanie do interfejsu, który reprezentuje kolekcję i chcesz metody add, powinieneś kodować do ICollection lub IList. Jako dodatkowy bonanza, interfejsy te implementują IEnumerable.

 4
Author: jason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-31 02:05:14

Przyszedłem tylko powiedzieć, że oprócz metody rozszerzenia Enumerable.Concat, wydaje się, że w.NET Core 1.1.1 istnieje inna metoda o nazwie Enumerable.Append. Ta ostatnia pozwala połączyć pojedynczy element z istniejącą sekwencją. Tak więc odpowiedź Aamola może być również zapisana jako

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

Należy jednak pamiętać, że ta funkcja nie zmieni sekwencji wejściowej, po prostu zwraca opakowanie, które umieszcza daną sekwencję i Dołączony element razem.

 3
Author: CXuesong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-10 11:18:00

Dasz radę.

//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;
 1
Author: Lrodriguez84,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-28 19:27:07

Najprostszym sposobem na to jest po prostu

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

Wtedy możesz zwrócić listę jako IEnumerable również dlatego, że implementuje on interfejs IEnumerable

 0
Author: Juha Sinkkonen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-28 11:49:36

Jasne, że możesz (zostawiam twój t-biznes na bok):

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

    return list.Select(i => i);
}
 -8
Author: Just N Observer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-06 15:26:28