代码之家  ›  专栏  ›  技术社区  ›  John

List.AddRange与IEnumerable<T>参数不工作?

  •  7
  • John  · 技术社区  · 13 年前

    我有以下场景,我想将一些项目添加到列表中。。。

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

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

    有人能澄清为什么会发生这种事吗?

    4 回复  |  直到 13 年前
        1
  •  4
  •   Reed Copsey    13 年前

    我想这是由于延迟执行,但我认为如果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> )。

        2
  •  3
  •   HatSoft    13 年前

    我本以为给定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
  •   Pablo Romeo    13 年前

    它确实有效。下面是一个单元测试来证明这一点:

    [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);
        }
    }
    

    也许在你的特定场景中有一些东西不能正常工作。

        4
  •  2
  •   John    13 年前

    谢谢你的回复。我试图简化这个例子的代码,但和往常一样,细节是魔鬼!

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

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

    推荐文章