上記のタイトルとして私の質問。例えば、
IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));
しかし、やはり内部には1つのアイテムしかありません。
items.Add(item)
のようなメソッドはありますか?
List<T>
のように
IEnumerable<T>
は必ずしも項目を追加できるコレクションを表すとは限らないため、できません。実際、これは必ずしもコレクションを表すものではありません。例えば:
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??
しかし、あなたができることは、 new IEnumerable
オブジェクト(未指定の型)を作成することです。これは、列挙されると、古いものすべてとあなた自身のものをすべて提供します。そのためにはEnumerable.Concat
を使用します。
items = items.Concat(new[] { "foo" });
この は配列オブジェクトを変更しません (とにかく配列に項目を挿入することはできません)しかし、それは新しいオブジェクトを作成し、それが配列内のすべての項目をリストし、次に "Foo"をリストします。さらに、その新しいオブジェクトは 配列の変更を追跡します (つまり、列挙するたびに、項目の現在の値が表示されます)。
IEnumerable<T>
型はそのような操作をサポートしません。 IEnumerable<T>
インターフェースの目的は、消費者がコレクションの内容を閲覧できるようにすることです。値を変更しないでください。
.ToList()。Add()のような操作をすると、新しいList<T>
を作成してそのリストに値を追加します。元のリストとは関係ありません。
あなたができることは、追加された値で新しいIEnumerable<T>
を作成するためにAdd extensionメソッドを使うことです。
items = items.Add("msg2");
この場合でも、元のIEnumerable<T>
オブジェクトは変更されません。これを参照することで確認できます。例えば
var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");
この一連の操作の後も、変数tempは値のセット内の単一の要素 "foo"を持つ列挙型のみを参照し、項目は値 "foo"と "bar"を持つ別の列挙型を参照します。
_編集_
私は、AddがIEnumerable<T>
の典型的な拡張方法ではないことを強く忘れています。なぜならそれは私が定義した最初のもののうちの1つだからです。ここにあります
public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
foreach ( var cur in e) {
yield return cur;
}
yield return value;
}
代わりに ICollection <T> または IList <T> インターフェイスを使用することを検討しましたが、それらはIEnumerable <T>で 'Add'メソッドを使用したいという非常に理由で存在します。 IEnumerable <T>は、実際の基礎となるオブジェクトが項目の追加/削除をサポートしているかどうかを必ずしも保証することなく、型を列挙型または一連の項目として 'マーク'するために使用されます。また、これらのインターフェースはIEnumerable <T>を実装しているので、IEnumerable <T>で得られるすべての拡張メソッドを取得できます。
IEnumerable
とIEnumerable<T>
の短い、簡潔な拡張方法は、私のためにそれをします:
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);
}
エレガント(まあ、非ジェネリックバージョンを除く)。残念ながら、これらのメソッドはBCLにはありません。
いいえ、IEnumerableはアイテムの追加をサポートしていません。
あなたは「代替」です:
var List = new List(items);
List.Add(otherItem);
2番目のメッセージを追加するにはあなたがする必要があります -
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})
.net Coreには、それを正確に行うメソッドEnumerable.Append
があります。
メソッドのソースコードは GitHubで入手できます。 ...(他の答えの提案よりも洗練された)実装は一見の価値があります:)。
あなたが言っているような項目を追加することができないだけでなく、既存の列挙子を持つList<T>
(またはほとんどすべての非読み取り専用コレクション)に項目を追加すると、列挙子は無効にされます(InvalidOperationException
あれから)。
何らかの種類のデータクエリの結果を集計する場合は、Concat
拡張メソッドを使用できます。
編集:私はもともとUnion
拡張子を使用していましたが、実際は正しくありません。私のアプリケーションでは、重複するクエリが結果を重複しないようにするためにこれを広く使用しています。
IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);
他の人たちは、なぜあなたがIEnumerable
にアイテムを追加することができない(そしてそうすべきではない!)のかについて、すでに素晴らしい説明をしています。コレクションを表すインターフェースへのコーディングを続け、addメソッドが必要な場合は、 ICollection
または IList
にコーディングする必要があります。追加の大当たりとして、これらのインターフェースはIEnumerable
を実装しています。
Enumerable.Concat
拡張メソッドの他に、.NET Core 1.1.1にはEnumerable.Append
という名前の別のメソッドがあるようです。後者では、単一のアイテムを既存のシーケンスに連結することができます。だからAamolの答えは次のように書くこともできます。
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));
それでも、この関数は入力シーケンスを変更しないことに注意してください。与えられたシーケンスと追加された項目をまとめたラッパーを返すだけです。
あなたはこれを行うことができます。
//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;
それをする最も簡単な方法は単純です
IEnumerable<T> items = new T[]{new T("msg")};
List<string> itemsList = new List<string>();
itemsList.AddRange(items.Select(y => y.ToString()));
itemsList.Add("msg2");
IEnumerableインターフェイスを実装しているため、IEnumerableとしてリストを返すこともできます。