List.AddRange与IEnumerable <t>参数不起作用?</t>

时间:2012-07-31 23:49:36

标签: c# list ienumerable deferred addrange

我有以下情况,我想在列表中添加一些项目......

List<T> items = new List<T>();
IEnumerable<T> addItems = someCollection.Where(...);
items.AddRange(addItems);

使用此代码,列表中不会添加任何项目,但如果我在Linq语句之后添加.ToList(),则会正确添加项目。我想这是由于延迟执行,但我想如果List.AddRange函数接受一个I​​Enumerable,它将枚举要添加的项目。

有人可以澄清为什么会这样吗?

4 个答案:

答案 0 :(得分:4)

  

我想这是由于延迟执行,但我认为,鉴于List.AddRange函数接受一个I​​Enumerable,它将枚举要添加的项目。

确实如此。 ICollection<T>有一个短路(在这种情况下你不会碰到它),这会导致它使用ICollection<T>.CopyTo而不是枚举项目,否则,它会枚举集合。 / p>

对于一个工作示例,请尝试:

using System;
using System.Linq;
using System.Collections.Generic;

internal class Program
{
    private static List<T> RunQuery<T>(IEnumerable<T> someCollection, Func<T, bool> predicate)
    {
        List<T> items = new List<T>();
        IEnumerable<T> addItems = someCollection.Where(predicate);
        items.AddRange(addItems);
        return items;
    }

    static void Main()
    {
        var values = Enumerable.Range(0, 1000);

        List<int> results = RunQuery(values, i => i >= 500);

        Console.WriteLine(results.Count);
        Console.WriteLine("Press key to exit:");
        Console.ReadKey();
    }
}

这会使用您的确切代码,并打印出500(List<T>中的正确数量的项目)。

答案 1 :(得分:2)

确实有效。这是一个证明它的单元测试:

[TestFixture]
public class AddRangeTest
{
    [Test]
    public void AddRange()
    {
        var list = new List<int>();
        var someCollection = new List<int> { 1, 2, 3 };
        var subItems = someCollection.Where(x => x > 1);
        list.AddRange(subItems);
        Assert.AreEqual(2, list.Count);
    }
}

也许您的特定场景中有些东西无法正常工作。

答案 2 :(得分:2)

  

我会想到,鉴于List.AddRange函数接受一个   IEnumerable它将枚举要添加的项目。

我尝试了以下内容,AddRange(IEnumerable<T>)确实有效

List<string> someCollection = new List<string>{"A", "B", "C"};
List<string> items = new List<string>();
IEnumerable<string> addItems = someCollection.Where(x => x != "");
items.AddRange(addItems);

答案 3 :(得分:2)

感谢您的回复。我试图简化这个例子的代码,但像往常一样,细节中的魔鬼!

在.Where()语句和AddRange()调用之间,代码是(内心深处)清除源(本例中为“items”)列表。开发人员没有意识到过滤器被推迟到AddRange()调用,此时他们已经清除了源列表。

很高兴知道我没有丢失情节:)