我的问题如上所述。例如,
IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));
但毕竟它里面只有1个项目。
我们可以使用像items.Add(item)
这样的方法吗?
与List<T>
答案 0 :(得分:429)
您不能,因为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??
然而,你可以做的是创建一个新的 IEnumerable
对象(未指定类型),当枚举时,它将提供旧项目的所有项目,以及一些你自己。您可以使用Enumerable.Concat
:
items = items.Concat(new[] { "foo" });
此不会更改数组对象(无论如何都不能将项目插入数组)。但它会创建一个新对象,列出数组中的所有项目,然后“Foo”。此外,该新对象将跟踪数组中的更改(即每当您枚举它时,您将看到项目的当前值)。
答案 1 :(得分:84)
类型IEnumerable<T>
不支持此类操作。 IEnumerable<T>
接口的目的是允许使用者查看集合的内容。不要修改值。
当您执行.ToList()。Add()等操作时,您正在创建新的List<T>
并向该列表添加值。它与原始列表没有关联。
您可以使用添加扩展程序方法创建具有附加值的新IEnumerable<T>
。
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>
上的典型扩展方法,因为它是我最终定义的第一个扩展方法之一。这是
public static IEnumerable<T> Add<T>(this IEnumerable<T> e, T value) {
foreach ( var cur in e) {
yield return cur;
}
yield return value;
}
答案 2 :(得分:48)
您是否考虑使用ICollection<T> 或IList<T>接口,它们的存在是因为您希望在IEnumerable&lt; T&gt;上使用“添加”方法。 IEnumerable的&LT; T&GT;用于将类型“标记”为......井......可枚举或仅仅是一系列项目,而不必保证真实底层对象是否支持添加/删除项目。还要记住,这些接口实现了IEnumerable&lt; T&gt;。因此,您将获得IEnumerable&lt; T&gt;所获得的所有扩展方法。同样。
答案 3 :(得分:29)
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中。
答案 4 :(得分:17)
没有IEnumerable不支持向其添加项目。
你'替代'是:
var List = new List(items);
List.Add(otherItem);
答案 5 :(得分:11)
要添加您需要的第二条消息 -
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})
答案 6 :(得分:10)
在.net Core中,有一种方法Enumerable.Append
就是这样做的。
该方法的源代码是available on GitHub. ....实现(比其他答案中的建议更复杂)值得一看:)。
答案 7 :(得分:8)
您不仅可以添加像您所说的项目,而且如果您将项目添加到List<T>
(或几乎任何其他非只读集合),您有一个现有的枚举器,则枚举器是无效(从此开始抛出InvalidOperationException
)。
如果要汇总某些类型的数据查询结果,可以使用Concat
扩展方法:
编辑:我最初在示例中使用了Union
扩展名,这实际上并不正确。我的应用程序广泛使用它来确保重叠查询不会重复结果。
IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);
答案 8 :(得分:4)
其他人已经给出了很好的解释,说明为什么你不能(也不应该!)能够将项目添加到IEnumerable
。我只想补充一点,如果您希望继续编写代表集合的接口并想要一个add方法,那么您应该编码为ICollection
或IList
。作为一个额外的富矿,这些接口实现IEnumerable
。
答案 9 :(得分:4)
我只是来这里说,除了Enumerable.Concat
扩展方法之外,.NET Core 1.1.1中似乎还有另一个名为Enumerable.Append
的方法。后者允许您将单个项目连接到现有序列。所以Aamol的答案也可以写成
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));
请注意,此函数不会更改输入序列,只返回一个将给定序列和附加项放在一起的包装器。
答案 10 :(得分:1)
你可以这样做。
//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;
答案 11 :(得分:1)
实现 IEnumerable 和 IEnumerator(从 IEnumerable 返回)的实例没有任何允许更改集合的 API,该接口提供只读 API。
实际更改集合的两种方法:
IList<string> list = enumerableInstance as IList<string>;
toList()
:var list = enumerableInstance.toList();
答案 12 :(得分:0)
最简单的方法就是
Data added in Inspectors.aspx
然后你可以将列表作为IEnumerable返回,因为它实现了IEnumerable接口
答案 13 :(得分:-1)
很抱歉,您的问题真的很老,但是由于它被列在第一批Google搜索结果中,因此我认为有些人一直在这里着陆。
在很多答案中,其中一些确实很有价值并且得到了很好的解释,我想补充一个不同的观点,因为对我而言,这个问题尚未得到很好的识别。
您要声明一个存储数据的变量,您需要它能够通过向其中添加项目来进行更改吗?因此,您不应使用将其声明为IEnumerable。
由@ NightOwl888提议
对于此示例,只需声明IList而不是IEnumerable:IList items = new T [] {new T(“ msg”)}; items.Add(new T(“ msg2”));
尝试绕过声明的接口限制仅表明您做出了错误的选择。 除此之外,应该考虑提议用于实现其他实现中已经存在的事物的所有方法。 用于添加项目的类和接口已经存在。为什么总是重建在其他地方已经做过的事情?
这种考虑是在接口内抽象变量功能的目标。
TL; DR:IMO这些是您所需的最干净的方法:
// 1st choice : Changing declaration
IList<T> variable = new T[] { };
variable.Add(new T());
// 2nd choice : Changing instantiation, letting the framework taking care of declaration
var variable = new List<T> { };
variable.Add(new T());
当您需要将变量用作IEnumerable时,便可以使用。当需要将其用作数组时,可以调用“ ToArray()”,它实际上应该总是那么简单。不需要扩展方法,仅在真正需要时才进行强制转换,可以在变量上使用LinQ,等等...
不要做奇怪和/或复杂的事情,因为您只是在声明/实例化时犯了一个错误。
答案 14 :(得分:-2)
下面的代码解决了我的问题。
material.MaterialCasualties = material.MaterialCasualties.Append(materialCasualties).ToList();
OR
customCustomer.CustomCustomerPayments = customCustomer.CustomCustomerPayments.Concat(customCustomerPayment).ToList();
答案 15 :(得分:-8)
当然,你可以(我将你的T-business留在一边):
public IEnumerable<string> tryAdd(IEnumerable<string> items)
{
List<string> list = items.ToList();
string obj = "";
list.Add(obj);
return list.Select(i => i);
}