23

I just realize that maybe I was mistaken all the time in exposing T[] to my views, instead of IEnumerable<T>.

Usually, for this kind of code:

foreach (var item in items) {}

item should be T[] or IEnumerable<T>?

Than, if I need to get the count of the items, would the Array.Count be faster over the IEnumerable<T>.Count()?

stacker
  • 14,641
  • 17
  • 46
  • 74

7 Answers7

34

IEnumerable<T> is generally a better choice here, for the reasons listed elsewhere. However, I want to bring up one point about Count(). Quintin is incorrect when he says that the type itself implements Count(). It's actually implemented in Enumerable.Count() as an extension method, which means other types don't get to override it to provide more efficient implementations.

By default, Count() has to iterate over the whole sequence to count the items. However, it does know about ICollection<T> and ICollection, and is optimised for those cases. (In .NET 3.5 IIRC it's only optimised for ICollection<T>.) Now the array does implement that, so Enumerable.Count() defers to ICollection<T>.Count and avoids iterating over the whole sequence. It's still going to be slightly slower than calling Length directly, because Count() has to discover that it implements ICollection<T> to start with - but at least it's still O(1).

The same kind of thing is true for performance in general: the JITted code may well be somewhat tighter when iterating over an array rather than a general sequence. You'd basically be giving the JIT more information to play with, and even the C# compiler itself treats arrays differently for iteration (using the indexer directly).

However, these performance differences are going to be inconsequential for most applications - I'd definitely go with the more general interface until I had good reason not to.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks for your answer. Can I assume that using `IEnumerable` and `Count()` is more efficient, then constructing an `T[]` just for getting the `Length` property? – stacker Aug 08 '10 at 07:19
  • @stacker: Creating a copy of a collection into an array just to get its length would certainly be less efficient than just calling `Count()`, yes. – Jon Skeet Aug 08 '10 at 08:09
  • How often do you need to get the number of elements? If you have to re-enumerate every element to get the `Count`, it could get expensive. – Gabe Aug 08 '10 at 13:43
  • @Gabe only once. I'm chancing it in a variable. – stacker Aug 08 '10 at 14:45
  • 1
    @stacker: IEnumerables can be infinite in theory, therefore they have no Count. Using an array you have Length. If you find yourself needing a count, use ICollection instead of IEnumerable. – Johannes Rudolph Aug 08 '10 at 18:45
  • @Johannes is using `ICollection` better than just use `count()`? – stacker Aug 08 '10 at 19:50
  • @stacker: If you use `Enumerable.Count`, that will notice if your collection implements `ICollection` and use the `Count` property automatically. It's not clear exactly what you're really getting at here. – Jon Skeet Aug 08 '10 at 19:57
  • @Johannes: I mean it's not quite clear what stacker is trying to achieve, or what he's concerned about. – Jon Skeet Aug 08 '10 at 20:15
  • @Jon: Ok, just wanted to make sure. And I couldn't resist the poetic tone of these words ;-) – Johannes Rudolph Aug 08 '10 at 20:53
  • @Jon thanks for the answer. I just want to make sure that it's better to use IEnumerable instead T[], instead the Model's, View Model's and Repositories. – stacker Aug 09 '10 at 00:05
7

It's partially inconsequential, but standard theory would dictate "Program against an interface, not an implementation". With the interface model you can change the actual datatype being passed without effecting the caller as long as it conforms to the same interface.

The contrast to that is that you might have a reason for exposing an array specifically and in which case would want to express that.

For your example I think IEnumerable<T> would be desirable. It's also worthy to note that for testing purposes using an interface could reduce the amount of headache you would incur if you had particular classes you would have to re-create all the time, collections aren't as bad generally, but having an interface contract you can mock easily is very nice.

Added for edit:
This is more inconsequential because the underlying datatype is what will implement the Count() method, for an array it should access the known length, I would not worry about any perceived overhead of the method. See Jon Skeet's answer for an explanation of the Count() implementation.

Community
  • 1
  • 1
Quintin Robinson
  • 81,193
  • 14
  • 123
  • 132
  • So, generally, I shouldn't use `T[]`, right? when *should* I use `T[]`? – stacker Aug 08 '10 at 06:28
  • @Quintin, C# arrays are not immutable. – Matthew Flaschen Aug 08 '10 at 06:33
  • @Matthew Flaschen That's one of the reasons why I said there are caveats, I didn't want to break it down, some perceive them to be immutable although you can modify the contents of the indices. – Quintin Robinson Aug 08 '10 at 06:36
  • @stacker Typically when you want to represent a perceived readonly collection or need the memory to be sequential. Of course there are caveats to this. – Quintin Robinson Aug 08 '10 at 06:44
  • @Quintin if it's immutable collection (perceived readonly), that need to be iterated (I didn't get what's `the memory to be sequential` mean), didn't IEnumerable better? This is exactly the case in my views. – stacker Aug 08 '10 at 06:45
  • @stacker Yes, like I said, for your purposes and probably for most general cases, `IEnumerable` is better suited. – Quintin Robinson Aug 08 '10 at 06:50
  • 2
    @stacker, you're correct. If you just want to access (not modify) the elements in consecutive order, `IEnumerable` is the correct choice. An array is appropriate when you want a fixed size collection and the ability to access and modify any element by index - [random access](http://en.wikipedia.org/wiki/Random_access). – Matthew Flaschen Aug 08 '10 at 06:54
  • @Quintin Through, is there any case that I want to `T[]`? I mean if I need it to be indexed, I can use `IList`. – stacker Aug 08 '10 at 06:54
  • @Matthew thanks for the link. I think you answered the question above. – stacker Aug 08 '10 at 06:58
3

T[] (one sized, zero based) also implements ICollection<T> and IList<T> with IEnumerable<T>.

Therefore if you want lesser coupling in your application IEnumerable<T> is preferable. Unless you want indexed access inside foreach.

Andrey Taptunov
  • 9,367
  • 5
  • 31
  • 44
3

Since Array class implements the System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T>, and System.Collections.Generic.IEnumerable<T> generic interfaces, I would use IEnumerable, unless you need to use these interfaces.

http://msdn.microsoft.com/en-us/library/system.array.aspx

Maksim Vi.
  • 9,107
  • 12
  • 59
  • 85
1

Your gut feeling is correct, if all the view cares about, or should care about, is having an enumerable, that's all it should demand in its interfaces.

Cirdec
  • 24,019
  • 2
  • 50
  • 100
0

What is it logically (conceptually) from the outside?

If it's an array, then return the array. If the only point is to enumerate, then return IEnumerable. Otherwise IList or ICollection may be the way to go.

If you want to offer lots of functionality but not allow it to be modified, then perhaps use a List internally and return the ReadonlyList returned from it's .AsReadOnly() method.

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
0

Given that changing the code from an array to IEnumerable at a later date is easy, but changing it the other way is not, I would go with a IEnumerable until you know you need the small spead benfit of return an array.

Ian Ringrose
  • 51,220
  • 55
  • 213
  • 317