如何将项添加到IEnumerable< T>采集?
-
06-07-2019 - |
题
我的问题如上所述。例如,
IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));
但毕竟它里面只有1个项目。
我们可以使用 items.Add(item)
?
与 List&lt; T&gt;
解决方案
您不能,因为 IEnumerable&lt; T&gt;
不一定代表可以添加项目的集合。事实上,它并不一定代表一个集合!例如:
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&lt; T&gt;
不支持此类操作。 IEnumerable&lt; T&gt;
接口的目的是允许消费者查看集合的内容。不要修改值。
当您执行.ToList()。Add()等操作时,您将创建一个新的 List&lt; T&gt;
并向该列表添加值。它与原始列表没有关联。
您可以使用添加扩展程序方法创建一个具有附加值的新 IEnumerable&lt; T&gt;
。
items = items.Add("msg2");
即使在这种情况下,它也不会修改原始的 IEnumerable&lt; T&gt;
对象。这可以通过保持对它的引用来验证。例如
var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");
在这组操作之后,变量temp仍将仅引用具有单个元素“foo”的枚举。在值集合中,项目将使用值“foo”引用不同的可枚举值。和“bar”。
修改强>
我不断忘记Add不是 IEnumerable&lt; T&gt;
的典型扩展方法,因为它是我最终定义的第一个。这是
public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
foreach ( var cur in e) {
yield return cur;
}
yield return value;
}
您是否考虑过使用 ICollection&lt; T&gt;
或 IList&lt; T&gt;
接口,它们的存在是因为您希望在 IEnumerable&lt; T&gt;
上有 Add
方法。
IEnumerable&lt; T&gt;
用于将类型“标记”为......井,可枚举或只是一系列项目,而不必保证真实底层对象是否支持添加/删除项目。还要记住,这些接口实现了 IEnumerable&lt; T&gt;
,因此您可以获得 IEnumerable&lt; T&gt;
所带来的所有扩展方法。
IEnumerable
和 IEnumerable&lt; T&gt;
上的几个简短的甜扩展方法为我做了:
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);
在.net Core中,有一个方法 Enumerable.Append
就是这样做的。
该方法的源代码是在GitHub上可用。 ....实现(比其他答案中的建议更复杂)值得一看:)。
要添加您需要的第二条消息 -
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})
您不仅可以添加像您所述的项目,还可以添加项目到 List&lt; T&gt;
(或几乎任何其他非只读集合)枚举器for,枚举器失效(从那时起抛出 InvalidOperationException
)。
如果要汇总某些类型的数据查询结果,可以使用 Concat
扩展方法:
编辑:我最初在示例中使用了 Union
扩展名,这实际上并不正确。我的应用程序广泛使用它来确保重叠查询不会重复结果。
IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);
我只是来这里说,除了 Enumerable.Concat
扩展方法之外,.NET Core 1.1.1中似乎还有另一个名为 Enumerable.Append
的方法。 。后者允许您将单个项目连接到现有序列。所以Aamol的答案也可以写成
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));
请注意,此函数不会更改输入序列,只返回一个将给定序列和附加项放在一起的包装器。
其他人已经给出了很好的解释,为什么你不能(而且不应该!)能够将项目添加到 IEnumerable
。我只想补充一点,如果你想继续编写代表集合的接口并想要一个add方法,你应该编写代码 ICollection
或 IList
。作为一个额外的富矿,这些接口实现了 IEnumerable
。
你可以这样做。
//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接口
当然,你可以(我将你的T-business留在一边):
public IEnumerable<string> tryAdd(IEnumerable<string> items)
{
List<string> list = items.ToList();
string obj = "";
list.Add(obj);
return list.Select(i => i);
}