当我编写DAL或其他返回一组项目的代码时,我是否应该总是返回声明:
public IEnumerable<FooBar> GetRecentItems()
或
public IList<FooBar> GetRecentItems()
目前,在我的代码中,我一直在尽量使用IEnumerable,但我不确定这是否是最佳做法?这似乎是正确的,因为我正在返回最通用的数据类型,同时仍然描述它的作用,但也许这是不正确的。
答案 0 :(得分:61)
当您需要返回可由调用者修改的集合或Collection的只读集合时,
框架设计指南建议使用类ReadOnlyCollection。
这是一个简单的IList首选的原因是IList不通知调用者它是否只读。
如果您返回IEnumerable<T>
,则某些操作可能对调用者来说有点棘手。此外,您不再为调用者提供修改集合的灵活性,这可能是您可能想要或不想要的。
请记住,LINQ包含一些技巧,并会根据执行的类型优化某些调用。因此,例如,如果您执行Count并且底层集合是List,则它不会遍历所有元素。
就个人而言,对于ORM,我可能会坚持使用Collection<T>
作为我的返回值。
答案 1 :(得分:41)
这实际上取决于您使用该特定界面的原因。
例如,IList<T>
有几种IEnumerable<T>
中没有的方法:
IndexOf(T item)
Insert(int index, T item)
RemoveAt(int index)
和属性:
T this[int index] { get; set; }
如果您以任何方式需要这些方法,那么请务必返回IList<T>
。
此外,如果使用 IEnumerable<T>
结果的方法期望IList<T>
,它将保留CLR不考虑所需的任何转换,从而优化编译的代码。
答案 2 :(得分:19)
这取决于......
返回最少派生类型(IEnumerable
)将为您提供最大的余地来改变基础实现。
返回更多派生类型(IList
)可为您的API用户提供更多结果操作。
我总是建议返回最少派生类型,其中包含您的用户将需要的所有操作...所以基本上,您首先必须在您定义的API的上下文中去除对结果的哪些操作有意义
答案 3 :(得分:19)
一般情况下,您应该要求最通用,并返回最具体的内容。因此,如果你有一个带参数的方法,并且你只需要IEnumerable中可用的那个,那么那应该是你的参数类型。如果您的方法可以返回IList或IEnumerable,则更喜欢返回IList。这确保了最广泛的消费者可以使用它。
在你需要的东西上松散,并明确你所提供的东西。
答案 4 :(得分:9)
要考虑的一件事是,如果您使用延迟执行LINQ语句来生成IEnumerable<T>
,则在从方法返回之前调用.ToList()
意味着您的项目可能会被迭代两次 - 一次创建列表,一旦调用者循环,过滤或转换您的返回值。在实际应用中,我希望避免将LINQ-to-Objects的结果转换为具体的List或Dictionary,直到我不得不这样做。如果我的调用者需要一个List,那就是一个简单的方法调用 - 我不需要为他们做出决定,这使得我的代码在调用者正在做foreach的情况下稍微更有效。
答案 5 :(得分:7)
List<T>
为调用代码提供了更多功能,例如修改返回的对象和按索引访问。因此,问题可归结为:在您的应用程序的特定用例中,您是否希望支持此类用途(可能是通过返回一个新构建的集合!),以便调用者方便 - 或者您是否希望速度为简单的情况下所有调用者需要循环遍历集合,你可以安全地返回对真实底层集合的引用,而不用担心会错误地改变它等等吗?
只有你能回答这个问题,并且只能理解你的来电者想要对返回值做什么,以及这里的表现有多重要(你要复制的收藏有多大,这有多大可能性)瓶颈等等。
答案 6 :(得分:4)
我认为你可以使用其中任何一个,但每个都有用。基本上
List
是IEnumerable
,但你有Parent
计数功能,添加元素,删除元素IEnumerable对于计算元素
效率不高
如果集合只是为了只读,或者集合的修改由IList
控制,那么只为Count
返回Count()
不是一个好主意。
在Linq中,IEnumerable<T>
上有一个.Count
扩展方法,如果基础类型为IList
,则CLR内部将快捷方式manufacturer.Models.Add(model)
,因此性能差异为可以忽略不计。
一般来说,我觉得(意见)最好在可能的情况下返回IEnumerable,如果你需要做添加,然后将这些方法添加到父类,否则消费者会在Model中管理违反原则的集合,例如: public interface IManufacturer
{
IEnumerable<Model> Models {get;}
void AddModel(Model model);
}
违反了德米特定律。当然,这些只是指导方针,而不是硬性规定,但在您完全掌握适用性之前,盲目追求比完全不遵循要好。
{{1}}
(注意:如果使用nNHibernate,您可能需要使用不同的访问器映射到私有IList。)
答案 7 :(得分:1)
当你谈论返回值而不是输入参数时,这并不是那么简单。当它是输入参数时,您确切地知道您需要做什么。因此,如果您需要能够遍历集合,则需要使用IEnumberable,而如果需要添加或删除,则需要使用IList。
在返回值的情况下,它更难。你的来电者期待什么?如果你返回一个IEnumerable,那么他就不会知道他可以从中做出一个IList。但是,如果你返回一个IList,他就会知道他可以迭代它。因此,您必须考虑调用者将对数据执行的操作。调用者需要/期望的功能是在决定返回什么时应该管理的内容。
答案 8 :(得分:0)
我认为你可以使用其中任何一个,但每个都有用。基本上List
是IEnumerable
,但您有计数功能,添加元素,删除元素
IEnumerable
对于计算元素或获取集合中的特定元素效率不高。
List
是一个非常适合查找特定元素,易于添加元素或删除元素的集合。
一般情况下,我尝试尽可能使用List
,因为这会给我更大的灵活性。
使用
List<FooBar> getRecentItems()
而不是
IList<FooBar> GetRecentItems()
答案 9 :(得分:0)
答案 10 :(得分:0)
如果不计算外部代码,最好还是返回IEnumerable,因为稍后您可以更改实现(不受外部代码影响),例如, yield iterator 逻辑和保存内存资源(顺便提一下非常好的语言功能)。
但是,如果您需要项目计数,请不要忘记IEnumerable和IList之间还有另一层 - ICollection 。
答案 11 :(得分:0)
我可能有点偏离这里,看到目前为止没有其他人建议,但为什么不返回(I)Collection<T>
?
根据我的记忆,Collection<T>
是List<T>
的首选返回类型,因为它抽象了实现。他们都实现IEnumerable
,但这对我来说听起来有点太低了。
答案 12 :(得分:0)
我认为一般规则是使用更具体的类来返回,以避免做不需要的工作并为调用者提供更多选项。
那就是说,我认为考虑你正在编写的代码比下一个人编写的代码(在合理范围内)更重要。这是因为你可以对已经存在的代码做出假设。
请记住,从界面中的IEnumerable向上移动到集合将起作用,从集合向下移动到IEnumerable会破坏现有代码。
如果这些意见似乎都有冲突,那是因为这个决定是主观的。
答案 13 :(得分:0)
List
)作为回报
值和输入参数的最通用类型,即使是集合也是如此。IReadOnlyList
或IReadOnlyCollection
作为返回值类型。