最近我有一项工作要处理FxCop警告之一- 不要公开通用列表 。因此,我尝试将List<T>
更改为ICollection<T>
。但是稍后,在进行单元测试时,我发现AddRange()
不能正常工作。并没有将元素的集合添加到集合对象中。
这是示例代码
gc.ToList().AddRange(sampleList);
我有两个问题要问
为什么不将项目添加到集合中。 下面是代码:
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();
}
}
List<T>
继承自ICollection<T>
,而List<T>
具有AddRange()
等功能。当我尝试将父级引用(ICollection<T>
)转换为子类对象(List<T>
)时,为何Intellisense不建议AddRange()
。相反,我需要执行.ToList()
,然后显示AddRange()
。
我为此进行了大量搜索。但是找不到令我满意的原因。因此,请帮助我理解。这将是很大的帮助。
答案 0 :(得分:2)
AddRange()
方法工作正常。问题是,您没有仔细阅读ToList()
扩展方法的文档,因此也没有意识到ToList()
方法返回一个全新的对象。 / p>
从IEnumerable
创建列表 。
由于您调用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()
更好。 / p>
将ICollection<T>
引用返回到其基础List<T>
(如另一个答复者建议的那样)是没有意义的,因为这样做首先会否定使用ICollection<T>
接口的任何值。
至少在实际需要修改集合的任何情况下,都将引用保留为List<T>
。 (仅使用ICollection<T>
在其他情况下公开该列表是很好的,甚至可能是有益的,但这是完全不同的讨论。)
只要我在回答,我就会提到我很怀疑您是否正确理解了FxCop警告的意图,因为公开通用列表本身并没有内在的危害。
答案 1 :(得分:1)
ToList()
返回一个新实例,这就是为什么您无法在“ gc”中看到AddRange的结果的原因。如果您确实要使用AddRange,则可以执行以下操作。
((List<GenericClass>)gc).AddRange(sampleList);