C# 为什么IEnumerable<;T>;。托利斯特<;T>;()返回列表<;T>;而不是IList<;T>;?
扩展方法C# 为什么IEnumerable<;T>;。托利斯特<;T>;()返回列表<;T>;而不是IList<;T>;?,c#,linq,interface,ienumerable,C#,Linq,Interface,Ienumerable,扩展方法ToList()返回一个列表。按照相同的模式,ToDictionary()返回一个字典 我很好奇为什么这些方法不分别将返回值键入IList和IDictionary。这似乎更奇怪,因为ToLookup将其返回值键入接口而不是实际实现 查看使用或其他反编译器的这些扩展方法的源代码,我们看到以下实现(显示ToList(),因为它较短): 公共静态列表ToList(此IEnumerable源代码){ if(source==null)抛出错误.ArgumentNull(“source”); 返回新
ToList()
返回一个列表。按照相同的模式,ToDictionary()
返回一个字典
我很好奇为什么这些方法不分别将返回值键入IList
和IDictionary
。这似乎更奇怪,因为ToLookup
将其返回值键入接口而不是实际实现
查看使用或其他反编译器的这些扩展方法的源代码,我们看到以下实现(显示ToList()
,因为它较短):
公共静态列表ToList(此IEnumerable源代码){
if(source==null)抛出错误.ArgumentNull(“source”);
返回新列表(源);
}
那么,为什么这个方法将其返回值键入接口的特定实现,而不是接口本身呢?唯一的变化是返回类型
我很好奇,因为除了这两种情况外,IEnumerable
扩展的签名非常一致。我总是觉得有点奇怪
此外,为了让事情变得更加混乱,国家:
根据
指定的键选择器功能
但是返回类型是ILookup
在中,Jon Skeet提到返回类型是List
,而不是IList
,但没有进一步涉及主题。
广泛的搜索没有找到答案,所以我在此问你:
不将返回值作为接口键入的背后是否有任何设计决策,或者这只是偶然现象?通常,当您在寻找具体类型的方法上调用ToList()时,否则该项可以保持为IEnumerable类型。除非您正在做需要具体列表的事情,否则不需要转换为列表。返回List
的优点是List
的那些不属于IList
的方法很容易使用。使用列表
可以做很多事情,但使用IList
却做不到
相比之下,Lookup
只有一个可用的方法,ILookup
没有(ApplyResultSelector
),而且你可能不会最终使用它。这些决策可能会让人觉得随意,但我猜ToList()
返回List
而不是接口,因为List
都实现了IList
,但它添加了常规IList
类型对象中不存在的其他成员
例如,AddRange()
查看IList应实现的功能():
公共接口IList:ICollection,
IEnumerable,IEnumerable
和列表
():
公共类列表:IList、ICollection、,
IList、ICollection、IReadOnlyList、IReadOnlyCollection、IEnumerable、,
数不清
也许您自己的代码不需要IReadOnlyList
、IReadOnlyCollection
或ICollection
,但.NET Framework和其他产品上的其他组件可能依赖于更专门的列表对象,这就是.NET开发团队决定不返回接口的原因
不要觉得总是返回一个接口是最好的做法。这取决于您的代码或第三方代码是否需要这样的封装。在我看来,返回列表
是合理的,因为方法名称是ToList
。否则它将不得不被命名为“卫浴者”。此方法的目的就是将非特定的IEnumerable
转换为特定类型的列表
如果您有一个名称不明确的方法,比如GetResults
,那么像IList
或IEnumerable
这样的返回类型对我来说似乎是合适的
如果您查看带有reflector的查找
类的实现,您将看到许多内部
成员,这些成员只能由LINQ本身访问。没有公共构造函数,查找
对象是不可变的。因此,直接公开查找
没有任何好处
Lookup
类似乎是一种LINQ内部类,并不用于公共用途。与IList相比,仅仅拥有列表
有许多优点。首先,List
有IList
没有的方法。您还知道实现是什么,它允许您对其行为进行推理。你知道它可以有效地添加到末尾,但不是开始,你知道它的索引器非常快,等等
您不必担心您的结构被更改为LinkedList
,从而破坏应用程序的性能。当涉及到这样的数据结构时,在相当多的上下文中,了解数据结构是如何实现的非常重要,而不仅仅是它遵循的契约。这是不应该改变的行为
您也不能将IList
传递给接受列表的方法,这是您经常看到的ToList
经常被使用,因为此人确实需要一个List
的实例来匹配他们无法控制的签名,而IList
对此没有帮助
然后我们问自己返回IList
有什么好处。我们可能会返回列表的其他实现,但正如前面提到的,这可能会产生非常有害的后果,几乎可以肯定,这比使用任何其他类型的列表可能获得的收益要多得多。使用接口而不是实现可能会给您带来温暖的模糊感,但即便如此
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
return new List<TSource>(source);
}
public interface IList<T> : ICollection<T>,
IEnumerable<T>, IEnumerable
public class List<T> : IList<T>, ICollection<T>,
IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>,
IEnumerable
public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable{
}
public static IList<TSource> ToIList<TSource>(this IEnumerable<TSource> source)
{
if (source == null) throw new ArgumentNullException(source);
return source.ToList();
}
[SerializableAttribute]
public class List<T> : IList<T>, ICollection<T>, IList, ICollection,
IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable