【问题标题】:List.AddRange with IEnumerable<T> parameter not working?带有 IEnumerable<T> 参数的 List.AddRange 不起作用?
【发布时间】:2012-07-29 20:15:17
【问题描述】:

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

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

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

有人能解释一下为什么会这样吗?

【问题讨论】:

  • 你怎么看“没有添加项目”,因为它应该添加项目?
  • someCollection 的类型是什么?请提供实际工作的代码,我不太确定需要在哪里添加 ToList。是否 someCollection IQueryable 以及是否可能存在未正确实施的 Linq 提供程序?

标签: c# list ienumerable deferred addrange


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    我原以为 List.AddRange 函数接受一个 IEnumerable,它将枚举要添加的项目。

    我尝试了以下方法,AddRange(IEnumerable&lt;T&gt;) 确实有效

    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】:

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

      [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】:

        我猜这是由于延迟执行造成的,但我原以为 List.AddRange 函数接受一个 IEnumerable,它会枚举要添加的项目。

        确实如此。 ICollection&lt;T&gt; 短路(在这种情况下您不会遇到),这将导致它使用 ICollection&lt;T&gt;.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&lt;T&gt; 中的正确项目数)。

        【讨论】:

        • 也许 OP 示例中的 someCollection 是某种类型,它使用空定义实现了 CopyTo
        • @DanTao 是的 - 可能还有其他事情发生。但是,一般来说,这确实适用于 IEnumerable&lt;T&gt; - 它不是“延迟执行”问题。
        • @DanTao(请注意,它需要 OP 有自己的“Where”方法来创建 ICollection&lt;T&gt; 的奇怪实现)
        • 对。似乎更可能是 OP 搞错了……但谁知道呢。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-08
        • 2014-09-16
        • 1970-01-01
        • 1970-01-01
        • 2021-06-21
        • 1970-01-01
        相关资源
        最近更新 更多