我只是意识到,在将T[]
公开给我的观点而不是IEnumerable<T>
时,我可能总是错了。
通常,对于这种代码:
foreach (var item in items) {}
item
应为T[]
或IEnumerable<T>
?
如果我需要获取项目的计数,那么Array.Count
会比IEnumerable<T>.Count()
更快吗?
答案 0 :(得分:31)
IEnumerable<T>
通常是更好的选择。但是,我想提出一点Count()
。当他说类型本身实现Count()
时,Quintin是不正确的。它实际上是在Enumerable.Count()
中作为扩展方法实现的,这意味着其他类型不会覆盖它以提供更有效的实现。
默认情况下,Count()
必须遍历整个序列以计算项目。但是,它 了解ICollection<T>
和ICollection
,并针对这些情况进行了优化。 (在.NET 3.5 IIRC中,它仅针对ICollection<T>
进行了优化。)现在数组实现了,因此Enumerable.Count()
遵循ICollection<T>.Count
并避免迭代整体序列。它仍然比直接调用Length
稍慢,因为Count()
必须发现它实现ICollection<T>
开始 - 但至少它仍然是O(1)。
对于一般性能来说,同样的事情也是如此:当迭代数组而不是一般序列时,JITted代码可能会更紧凑。您基本上可以为JIT提供更多信息,甚至C#编译器本身也会以不同的方式处理数组(直接使用索引器)。
然而,这些性能差异对于大多数应用程序来说都是无关紧要的 - 我肯定会使用更通用的界面,直到我有充分的理由不这样做。
答案 1 :(得分:5)
这部分无关紧要,但标准理论将规定“针对接口的程序,而不是实现”。使用接口模型,只要符合相同的接口,就可以更改传递的实际数据类型,而不会影响调用者。
与此形成鲜明对比的是,您可能有理由专门公开数组,并且在这种情况下需要表达它。
对于您的示例,我认为IEnumerable<T>
是可取的。还值得注意的是,出于测试目的,使用界面可以减少您在特定课程中所产生的头痛量,您必须一直重新创建,集合通常不是那么糟糕,但有接口合同你可以轻松地模拟是非常好的。
添加编辑:
这是无关紧要的,因为基础数据类型将实现
See Jon Skeet's answer有关Count()
方法,对于应该访问已知长度的数组,我不担心方法的任何感知开销。Count()
实施的解释。
答案 2 :(得分:3)
T [](一个大小,基于零)也使用ICollection<T>
实现IList<T>
和IEnumerable<T>
。
因此,如果您希望在应用程序中使用较少的耦合IEnumerable<T>
,则更可取。除非您想在 foreach 中进行索引访问。
答案 3 :(得分:2)
由于Array类实现了System.Collections.Generic.IList<T>
,System.Collections.Generic.ICollection<T>
和System.Collections.Generic.IEnumerable<T>
通用接口,我将使用IEnumerable,除非您需要使用这些接口。
答案 4 :(得分:1)
如果所有观点都关心或者应该关心的话,那么你的直觉就是正确的,这就是它的界面所需要的一切。
答案 5 :(得分:0)
从外部逻辑上(概念上)是什么?
如果是数组,则返回数组。如果唯一的一点是枚举,则返回IEnumerable。否则IList或ICollection可能就好了。
如果你想提供很多功能但不允许修改它,那么也许在内部使用List并返回从它的.AsReadOnly()方法返回的ReadonlyList。
答案 6 :(得分:0)
鉴于稍后将代码从数组更改为IEnumerable很容易,但是改变它的方式不是,我会使用IEnumerable,直到你知道你需要返回数组的小spead benfit。 / p>