IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));
但毕竟它只有一个项目。我们是否可以像List<T>
那样拥有一个items.Add(item)
的方法?与此类似。
IEnumerable<T> items = new T[]{new T("msg")};
items.ToList().Add(new T("msg2"));
但毕竟它只有一个项目。我们是否可以像List<T>
那样拥有一个items.Add(item)
的方法?与此类似。
你不能这样做,因为 IEnumerable<T>
并不一定表示可以添加项目的集合。实际上,它甚至不一定表示一个集合!例如:
IEnumerable<string> ReadLines()
{
string s;
do
{
s = Console.ReadLine();
yield return s;
} while (!string.IsNullOrEmpty(s));
}
IEnumerable<string> lines = ReadLines();
lines.Add("foo") // so what is this supposed to do??
不过,你可以创建一个新的IEnumerable
对象(未指定类型),当枚举时,将提供旧对象的所有项以及一些你自己添加的项。你可以使用 Enumerable.Concat
实现:
items = items.Concat(new[] { "foo" });
这个操作不会改变数组对象(无论如何你都不能向数组中插入项)。但它将创建一个新的对象,其中列出了数组中的所有项,然后是 "Foo"。此外,该新对象将跟踪数组中的更改(即,每当枚举它时,您将看到项当前的值)。
Concat
被重复循环调用,那么这么做可能是值得的,但我认为这是过早优化的表现。而且如果确实需要这样做,那么你可能会遇到更大的问题,因为每次调用Concat
都会增加一个枚举器层级,因此最终单个MoveNext
调用将导致与迭代次数相同长度的调用链。 - Pavel MinaevIEnumerable<T>
的语法糖的Connect特性请求,其中包括将operator+
重载为Concat
(顺便说一下,在VB中,您可以像使用数组一样索引IEnumerable
,它在幕后使用了ElementAt
): https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=375929。如果我们还可以得到两个重载版本的`Concat`,分别在左侧和右侧都接受单个项目,那么这将把输入缩减到`xs +=x` - 因此请去找Mads(Torgersen),让他优先考虑在C# 5.0中实现这个功能 :) - Pavel Minaev类型 IEnumerable<T>
不支持这些操作。 IEnumerable<T>
接口的目的是允许使用者查看集合的内容。 而不是修改内容。
当您执行像 .ToList().Add() 这样的操作时,您正在创建一个新的 List<T>
并向该列表添加值。 它与原始列表没有任何连接。
您可以使用Add扩展方法来创建一个新的 IEnumerable<T>
,其中包含添加的值。
items = items.Add("msg2");
即使在这种情况下,它也不会修改原始的 IEnumerable<T>
对象。可以通过保留对其的引用来验证这一点。例如:
var items = new string[]{"foo"};
var temp = items;
items = items.Add("bar");
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;
}
Add
都会对集合进行原地修改。或许可以用 With
?或者甚至可以作为 Concat
的另一个重载。 - Pavel MinaevConcat
重载可能是更好的选择,因为 Add
通常暗示着可变性。 - Dan Abramovreturn e.Concat(Enumerable.Repeat(value,1));
如何? - Roy TinkerList.Add
不返回List
,而是改变原始列表,而您的扩展方法IEnumerable.Add
返回IEnumerable
,但不会改变原始列表。这种行为差异足以使我认为“Add”是一个不可取的名称。 - ErikEICollection<T>
或IList<T>
接口呢?它们的存在就是为了让你在IEnumerable<T>
上拥有Add
方法。
IEnumerable<T>
用于标记类型为可枚举类型或仅仅是项的序列,而不一定保证底层对象是否支持添加/删除项。同时要记住,这些接口实现了IEnumerable<T>
,因此您还可以获得所有与IEnumerable<T>
相关的扩展方法。.Net Core 中有一个名为Enumerable.Append
的方法,它正是你所需要的。
该方法的源代码可以在GitHub 上获得...... 该实现(比其他答案中的建议更为复杂)值得一看 :)。
对于我来说,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);
}
ToString()
操作,因为这样可以捕获更多的错误详细信息。我猜你没有在文件顶部包含System.Linq;
,但是谁知道呢?如果你无法解决问题,请尝试创建一个最小的原型来展示相同的错误,然后在提问中寻求帮助。 - user1228不,IEnumerable
不支持向其中添加项。替代方案是
var myList = new List(items);
myList.Add(otherItem);
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Concat(new[] {new T("msg2")})
除了Enumerable.Concat
扩展方法之外,.NET Core 1.1.1 中似乎还有另一种名为Enumerable.Append
的方法。后者允许您将单个项目连接到现有序列中。因此,Aamol的答案也可以写成:
IEnumerable<T> items = new T[]{new T("msg")};
items = items.Append(new T("msg2"));
请注意,此函数不会改变输入序列,它只返回一个包装器,将给定的序列和追加的项放在一起。
不能像你所说的那样添加项目,而且如果你向List<T>
(或几乎任何其他非只读集合)添加项目,并且你有一个现有的枚举器,那么枚举器将无效(从那时起会抛出 InvalidOperationException
异常)。
如果您正在聚合某种类型的数据查询结果,则可以使用Concat
扩展方法:
编辑:我最初在示例中使用了Union
扩展,这实际上是不正确的。我的应用程序广泛使用它来确保重叠查询不重复结果。
IEnumerable<T> itemsA = ...;
IEnumerable<T> itemsB = ...;
IEnumerable<T> itemsC = ...;
return itemsA.Concat(itemsB).Concat(itemsC);
其他人已经对为什么不能(也不应该!)向 IEnumerable
添加项目给出了很好的解释。我只想补充一点,如果您想继续编写代表集合的接口并想要添加方法,则应编写 ICollection
或 IList
。作为额外的奖励,这些接口实现了 IEnumerable
。
IEnumerable<T>
仅用于查询集合,是 LINQ 框架的核心。它始终是其他集合类型(如Collection<T>
、List<T>
或Array
)的抽象表示。该接口只提供了一个GetEnumerator
方法,返回一个IEnumerator<T>
实例,使得能够一次迭代扩展集合中的一个项。由于该接口的限制,LINQ 扩展方法也受到了限制。IEnumerable<T>
被设计成只读的,因为它可能代表多个集合部分的聚合。 - JordanIList<T>
而不是IEnumerable<T>
:IList<T> items = new T[]{new T("msg")}; items.Add(new T("msg2"));
- NightOwl888