我有以下场景,我想向列表中添加一些项。。。
List<T> items = new List<T>();
IEnumerable<T> addItems = someCollection.Where(...);
items.AddRange(addItems);
使用此代码,不会将任何项添加到列表中,但如果在Linq语句之后添加.ToList(),则会正确添加这些项。我想这是由于延迟执行,但我认为如果List.AddRange函数接受IEnumerable,它会枚举要添加的项。
有人能澄清为什么会发生这种事吗?
我想这是由于延迟执行,但我认为如果List.AddRange函数接受IEnumerable,它会枚举要添加的项。
确实如此。ICollection<T>
短路(在这种情况下不会碰到),这将导致它使用ICollection<T>.CopyTo
而不是枚举项,但否则,它将枚举集合。
对于一个工作示例,请尝试:
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>
中的正确项目数)。
我本以为给定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);
它确实有效。这里有一个单元测试证明了这一点:
[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);
}
}
也许在你的特定场景中有一些东西不能正常工作。
感谢您的回复。我试着简化这个例子的代码,但和往常一样,关键在于细节!
在.Where()语句和AddRange()调用之间,代码正在(深层次)清除源(本例中为"items")列表。开发人员没有意识到过滤器被推迟到AddRange()调用,此时他们已经清除了源列表。
很高兴知道我没有失去这个情节:)