The main reason to develop any type implementing
System.Collections.IEnumerable
,
http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx[
^], is to introduce the possibility of traversing some set of objects through
forеаch
statement:
http://msdn.microsoft.com/en-us/library/ttw7t8t6%28v=vs.110%29.aspx[
^],
http://msdn.microsoft.com/en-us/library/9yb8xew9.aspx[
^].
If you don't need this, you don't have to implement this interface. This is an interesting example for you. Despite of the keyword "
enum
", .NET enumeration type do not implement enumeration through those declared (static) type members. To use
foreach
, you would need to iterate through its values (for example), but in general case, this is not exactly the same. To introduce
foreach
traversing those members (not anything else), I created a separate generic type using user's enumeration type as a generic parameter. This generic type provides comprehensive information of this enumeration type and enables
foreach
through the implementation of
System.Collections.IEnumerable
, as explained in the article:
Enumeration Types do not Enumerate! Working around .NET and Language Limitations[
^].
It can give you a very general idea of the utility of this interface you could be able to apply to a wide range of data structures representing any arbitrary data sets.
[EDIT #1]
As a method parameter? As always with interface-type parameters, this is good to abstract out from the implementation. The method with such parameter will be able to traverse through the set accessible via
forarch
and access each element in this set. In many cases, this is all what matters.
This idea is not limited to parameter passing. This is just the general approach based on abstraction. If too related objects depend on each other, or one depends on another, the depending object may need a reference member pointing to another object. Depending on the purpose of dependency, very often, the reference does not need to be a class or structure type, because only small part of functionality should be exposed. In this case, interfaces come very handy.
[EDIT #2]
Performance of
foreach
is almost totally depends on the performance of the implementation of
System.Collections.IEnumerator
. As you can see, the only role of
IEnumerable
is to provide an access to the reference to
IEnumerator
which makes the major job:
http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.getenumerator.aspx[
^],
http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.aspx[
^].
Almost everything depends on what the implementation of
IEnumerator.Current
and
IEnumerator.MoveNext
do. These method can access the elements of the set in a very simple way like indexing (in arrays or
System.Collections.Generic.List
, but they can also perform complex calculations, query something, etc. Even the reference to the element to be returned might not be available immediately, so the algorithm calculates out the required object on the fly. If sounds not wise, but there are certain cases when this makes sense. You need to understand what happens in each implementation.
Actually, I would like to give you another advice. Not always you can trust your own judgement on performance. To gain some experience and get better idea on performance, you can simple time some operations. The most accurate tool for that it the class
System.Diagnostics.Stopwatch
.
There is one catch specific to .NET (CLI) though. You need to take into account the time taken by JIT. Most usually, the code is JIT-compiled on per-method basis. So, the method is usually JIT-compiled when a method is about to be called for the very first time in the process life time. Be careful not to include the first call in timing. Please see:
http://en.wikipedia.org/wiki/Just-in-time_compilation[
^],
http://msdn.microsoft.com/en-us/magazine/cc163791.aspx[
^],
http://msdn.microsoft.com/en-us/library/k5532s8a.aspx[
^].
If you time things sometime, some results will come at surprise to you. However, you should not get into this activity too much: it is needed only to get some idea and to reveal the bottlenecks. There are usually to few bottlenecks. Most performance issues are related to general code design way more than to fine implementation detail.
—SA