Ma question comme titre ci-dessus. Par exemple,
IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));
mais après tout, il ne contient qu'un seul article à l'intérieur.
Pouvons-nous avoir une méthode comme items.Add(item)
?
comme le List<T>
Vous ne pouvez pas, car IEnumerable<T>
ne représente pas nécessairement une collection à laquelle des éléments peuvent être ajoutés. En fait, cela ne représente pas nécessairement une collection du tout! Par exemple:
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??
Ce que vous pouvez faire, cependant, est de créer un objet nouveaIEnumerable
(de type non spécifié), qui, une fois énuméré, fournira tous les éléments de l'ancien, plus les vôtres. Vous utilisez Enumerable.Concat
pour cela:
items = items.Concat(new[] { "foo" });
Ceci ne changera pas l'objet tablea (de toute façon, vous ne pouvez pas insérer d'éléments dans les tableaux). Mais cela créera un nouvel objet qui listera tous les éléments du tableau, puis "Foo". En outre, ce nouvel objet suivra les modifications dans le tablea (c’est-à-dire que chaque fois que vous l’énumérerez, vous verrez les valeurs actuelles des éléments).
Le type IEnumerable<T>
ne prend pas en charge de telles opérations. Le but de l'interface IEnumerable<T>
est de permettre à un consommateur de voir le contenu d'une collection. Ne pas modifier les valeurs.
Lorsque vous effectuez des opérations telles que .ToList (). Add (), vous créez un nouveau List<T>
et ajoutez une valeur à cette liste. Il n'a aucun lien avec la liste d'origine.
Ce que vous pouvez faire est d'utiliser la méthode d'extension Add pour créer un nouveau IEnumerable<T>
avec la valeur ajoutée.
items = items.Add("msg2");
Même dans ce cas, il ne modifiera pas l'objet d'origine IEnumerable<T>
. Cela peut être vérifié en tenant une référence. Par exemple
var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");
Après cet ensemble d'opérations, la variable temp ne fera toujours référence qu'à un objet énumérable avec un seul élément "foo" dans l'ensemble de valeurs, tandis que les éléments feront référence à un objet énumérable différent avec les valeurs "foo" et "bar".
EDIT
J'oublie immédiatement que Add n'est pas une méthode d'extension typique sur IEnumerable<T>
parce que c'est l'une des premières que je définisse. C'est ici
public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
foreach ( var cur in e) {
yield return cur;
}
yield return value;
}
Avez-vous envisagé d'utiliser des interfaces ICollection<T>
ou IList<T>
, elles existent uniquement parce que vous souhaitez utiliser une méthode Add
sur un _IEnumerable<T>
_.
_IEnumerable<T>
_ est utilisé pour 'marquer' un type comme étant ... bien, énumérable ou simplement une séquence d'éléments sans nécessairement garantir que l'objet réel sous-jacent prend en charge l'ajout/la suppression d'éléments. N'oubliez pas non plus que ces interfaces implémentent _IEnumerable<T>
_ afin que vous obteniez également toutes les méthodes d'extensions que vous obtenez avec _IEnumerable<T>
_.
Quelques méthodes d’extension simples et douces sur IEnumerable
et IEnumerable<T>
le font pour moi:
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);
}
Élégant (enfin, sauf pour les versions non génériques). Dommage que ces méthodes ne figurent pas dans la BCL.
Non, l'IEnumerable ne prend pas en charge l'ajout d'éléments.
Vous 'alternative' c'est:
var List = new List(items);
List.Add(otherItem);
Dans .net Core, il existe une méthode Enumerable.Append
qui fait exactement cela.
Le code source de la méthode est disponible sur GitHub. .... L'implémentation (plus sophistiquée que les suggestions des autres réponses) mérite le détour :).
Pour ajouter un deuxième message, vous devez -
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})
Non seulement vous ne pouvez pas ajouter des éléments comme vous le dites, mais si vous ajoutez un élément à un List<T>
(ou à peu près toute autre collection non-lecture seule) pour lequel vous avez un énumérateur existant, celui-ci est invalidé InvalidOperationException
à partir de là).
Si vous agrégez les résultats d'un type de requête de données, vous pouvez utiliser la méthode d'extension Concat
:
Edit: À l'origine, j'avais utilisé l'extension Union
dans l'exemple, ce qui n'est pas vraiment correct. Mon application l'utilise beaucoup pour s'assurer que les requêtes qui se chevauchent ne dupliquent pas les résultats.
IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);
Je viens juste de dire ici que, mis à part la méthode d'extension Enumerable.Concat
, il semble exister une autre méthode appelée Enumerable.Append
dans .NET Core 1.1.1. Ce dernier vous permet de concaténer un seul élément à une séquence existante. Donc, la réponse d'Aamol peut aussi être écrite comme suit:
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));
Néanmoins, veuillez noter que cette fonction ne changera pas la séquence d'entrée, elle renverra simplement un wrapper qui assemble la séquence donnée et l'élément ajouté.
D'autres ont déjà fourni d'excellentes explications sur les raisons pour lesquelles vous ne pouvez pas (et ne devriez pas!) Pouvoir ajouter des éléments à un IEnumerable
. J'ajouterai seulement que si vous souhaitez continuer à coder sur une interface qui représente une collection et souhaitez utiliser une méthode add, vous devez coder en ICollection
ou IList
. En bonanza supplémentaire, ces interfaces implémentent IEnumerable
.
tu peux le faire.
//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;
Le moyen le plus simple de le faire est tout simplement
IEnumerable<T> items = new T[]{new T("msg")};
List<string> itemsList = new List<string>();
itemsList.AddRange(items.Select(y => y.ToString()));
itemsList.Add("msg2");
Ensuite, vous pouvez retourner list en tant que IEnumerable également car il implémente l'interface IEnumerable