我试图复制一个枚举用于比较的目的,因为将一个可枚举分配给另一个只是创建引用,所以第二个将像第一个那样改变。我初步认为使用linq Select会创建第二个可枚举但很惊讶地发现它最终只是传递了引用。
逻辑本身用于确定标记列表是否包含特定显示方案的相同事件,代码如下所示。
IEnumerable<Event> lastevents = null;
foreach (var tag in tags)
{
IEnumerable<Event> thisevents = events.Where(e => e.Tags.Contains(tag));
if (lastevents != null)
{
foreach (var item in thisevents)
{
if (!lastevents.Contains(item))
return true;
}
}
lastevents = thisevents.Select(e => e);
}
在这种情况下复制可枚举的最佳方法是什么?
答案 0 :(得分:3)
最简单的方法是致电ToList()
或ToArray()
。这两个实现查询。诸如Where
和Select
之类的LINQ运算符在可能的情况下是懒惰的 - 它们知道原始集合,并且仅在处理它们时处理数据。
当然,通过拨打ToList
/ ToArray
,您可以移除对Select
的呼叫,因为它基本上是无操作。
答案 1 :(得分:1)
选择不会复制引用,它会创建一个新的IEnumerable,但使用新的IEnumerable也会消耗原始的IEnumerable。你真正想要的是将它复制到列表中,这样你就可以再次枚举。
thisevents.ToList()
答案 2 :(得分:1)
要复制集合,它必须首先作为集合存在。
在您展示的代码中,thisevents
对象不是集合,它只是一个能够从源events
创建集合的表达式。每次使用thisevents
对象时,它都会通过处理events
中的数据来创建新结果。
使用Select
将创建一个处理源的表达式,并且在这种情况下源是一个处理events
的表达式,最终结果仍然是一个处理events
的表达式。使用Select
只会将表达式包装在另一个表达式中,它不会实现集合。
当您将表达式分配给lastevents
时,它仍然是一个处理events
的表达式,因此如果您更改events
,lastevents
的结果也会随着ToList
而变化在飞行中创建。
您可以使用ToArray
或IEnumerable<Event> lastevents = null;
foreach (var tag in tags) {
IEnumerable<Event> thisevents = events.Where(e => e.Tags.Contains(tag)).ToList();
if (lastevents != null) {
foreach (var item in thisevents) {
if (!lastevents.Contains(item)) {
return true;
}
}
}
lastevents = thisevents;
}
将结果具体化为实际集合:
thisevents
请注意,由于events
是一个不再依赖lastevents
的实际集合,因此将引用复制到{{1}}并不是一个问题。您不必创建该集合的另一个副本。