将列表项添加到Collection时,AddRange()不起作用

问题描述 投票:-2回答:2

最近我有一个任务要处理其中一个FxCop警告 - 不要暴露通用列表。所以我尝试将List<T>改为ICollection<T>。但是稍后的时间点,在进行单元测试时,我发现AddRange()没有按预期正常工作。它不是将集合元素添加到集合对象中。

这是示例代码

gc.ToList().AddRange(sampleList);

我有两个问题要问

  1. 为什么不将项目添加到集合中。以下是代码: public class GenericClass { public int Id; public string Name; } class Program { static void Main(string[] args) { ICollection<GenericClass> gc = new List<GenericClass>(); var sampleList = new List<GenericClass>() { new GenericClass {Id = 1, Name = "ASD"}, new GenericClass {Id = 2, Name = "QWER"}, new GenericClass {Id = 3, Name = "BNMV"}, }; Console.WriteLine(gc.GetType()); // gc is of type gc.ToList().AddRange(sampleList); // sampleList items are not getting added to gc. Console.ReadKey(); } }
  2. List<T>继承自ICollection<T>List<T>AddRange()等功能。当我试图将父级引用(ICollection<T>)转换为子类对象(List<T>)时,为什么Intellisense不建议使用AddRange()。相反,我需要做.ToList()然后它显示AddRange()Screenshot

我搜索了很多。但找不到让我满意的理由。所以请帮助我理解。这将是一个很大的帮助。

c# generics generic-collections
2个回答
2
投票

AddRange()方法工作正常。问题是,你没有仔细阅读ToList()扩展方法的文档,因此没有意识到ToList()方法返回一个全新的对象。

来自the documentation

从IEnumerable <T>创建List <T>。

由于您调用AddRange()的对象实际上不是原始集合,因此原始集合保持不变。

从某种意义上说,你的问题是List<T>相当于一个非常常见的问题“为什么string.Replace()不工作?”

在你给出的例子中,没有比仅仅隐藏List<T>更好的解决方案。你可以,因为你使用通用的ICollection<T>接口,编写自己的AddRange()作为扩展方法:

public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> range)
{
    foreach (T t in range)
    {
        collection.Add(t);
    }
}

但我不相信这比仅仅将类型保留为List<T>要好得多,如果目标是能够修改对象并使用AddRange()方法。

ICollection<T>引用转回其底层的List<T>(正如另一个回答者提议的那样)是毫无意义的,因为这样做会否定在使用ICollection<T>接口时的任何价值。

只需将引用保留为List<T>,至少在您确实需要修改集合的任何上下文中。 (只使用ICollection<T>在其他环境中公开该列表,这很好,甚至可能是有益的,但这是一个完全不同的讨论。)

只要我回答,我就会提到我怀疑你是否正确理解了FxCop警告的意图,因为暴露通用列表本身并不具有本质上的危害。


1
投票

ToList()返回一个新实例,这就是为什么你无法在“gc”中看到AddRange的结果。如果您确实想使用AddRange,则可以执行以下操作。

((List<GenericClass>)gc).AddRange(sampleList);
© www.soinside.com 2019 - 2024. All rights reserved.