我深入阅读了C# (第3版),在第13章中,在讨论在c# 4中包含协变和反变类型参数的一节中,提出了这样的主张:
List.AddRange的参数是IEnumerable类型,因此在本例中,您将每个列表视为以前不可能的IEnumerable -something。AddRange本来可以用自己的类型参数编写成一个泛型方法,但它不是这样做的--这样做会使一些优化变得困难或不可能。
有人能为这一说法提供一些理由吗?对我来说,为什么这是真的还不清楚。
发布于 2018-08-08 11:45:48
我想它不是像void AddRange<T>(IEnumerable<T> items)那样编写的,是因为它在IEnumerable<T>是ICollection<T>时所做的优化。当IEnumerable<T>是ICollection<T>时,AddRange内部调用ICollection<T>.CopyTo,其中的第一个参数是T[]。(请注意,List<T>的底层存储机制是T[])。
基类型的数组与派生类型的数组不相同,因此不能这样做,例如:
object[] objs = new object[4];
var collection = (new string[4]) as ICollection<string>;
collection.CopyTo(objs,0); //Cannot convert object[] to string[]这是一种“不可能”的优化。
您可以在这里查看源代码:https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,79de3e39e69a4811
似乎AddRange应该检查T[]和List<T>,并在这些情况下执行Array.Copy,但是-100,我想。您可能会对Array.ToArray()没有做的事情感到有些惊讶。
发布于 2018-08-08 10:42:57
我认为这样做的原因是,IEnumerable<T>可能只包含类型/实现接口T的对象,并且需要对AddRange<T2>中的每个元素进行检查。
让我们尝试一些可能与通用AddRange崩溃的代码。
public class MyClass1 : IFoo, IBar
{
/* some code */
}
public class MyClass2 : IFoo
{
/* some code */
}
var fooList = new List<IFoo>
{
new MyClass1(),
new MyClass2()
}
var barList = new List<IBar>();
barList.AddRange<IFoo>(fooList);现在,问题是,它应该如何反应?您可以将MyClass1的对象添加到barList,因为它实现了IBar,但是当您尝试添加MyClass2时会发生什么呢?在添加元素之前,我们需要检查列表中的每个元素,以防止抛出异常。
https://stackoverflow.com/questions/51744440
复制相似问题