复制IEnuemrable <t> - linq选择无法按预期运行</t>

时间:2010-11-22 10:49:58

标签: c# linq

我试图复制一个枚举用于比较的目的,因为将一个可枚举分配给另一个只是创建引用,所以第二个将像第一个那样改变。我初步认为使用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);
}

在这种情况下复制可枚举的最佳方法是什么?

3 个答案:

答案 0 :(得分:3)

最简单的方法是致电ToList()ToArray()。这两个实现查询。诸如WhereSelect之类的LINQ运算符在可能的情况下是懒惰的 - 它们知道原始集合,并且仅在处理它们时处理数据。

当然,通过拨打ToList / ToArray,您可以移除对Select的呼叫,因为它基本上是无操作。

答案 1 :(得分:1)

选择不会复制引用,它会创建一个新的IEnumerable,但使用新的IEnumerable也会消耗原始的IEnumerable。你真正想要的是将它复制到列表中,这样你就可以再次枚举。

thisevents.ToList()

答案 2 :(得分:1)

要复制集合,它必须首先作为集合存在。

在您展示的代码中,thisevents对象不是集合,它只是一个能够从源events创建集合的表达式。每次使用thisevents对象时,它都会通过处理events中的数据来创建新结果。

使用Select将创建一个处理源的表达式,并且在这种情况下源是一个处理events的表达式,最终结果仍然是一个处理events的表达式。使用Select只会将表达式包装在另一个表达式中,它不会实现集合。

当您将表达式分配给lastevents时,它仍然是一个处理events的表达式,因此如果您更改eventslastevents的结果也会随着ToList而变化在飞行中创建。

您可以使用ToArrayIEnumerable<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}}并不是一个问题。您不必创建该集合的另一个副本。