evildictaitor said:
wkempf said:
*snip*
Be aware that the reason Count and Random access are not provided in IEnumerable<> is quite deliberate - whereas random access and counting in a List<T> is fast, random access and counting in a LinkedList<> is not - furthermore, IEnumerable<T> allows some interesting properties - for example there's no reason why an IEnumerable<T> should actually ever terminate, and it's certainly not nessisarilly the case that it should know if (or when) it's going to terminate when it starts.

For example, if you're reading through a series of lines in a text file, there's a good argument to say that you only need to read them one at a time. Finding out how many lines there are requires you to read the entire file into memory (and the file may be big), but reading each line into memory one at a time does not require you to read all of the file into memory. Thus by using IEnumerable<T> rather than a Collection<T>, some benefit has been achieved.

Another example is when tokenising a HTML stream to be rendered - if we were to insist on knowing how many elements there were before we started, then we would need to start parsing after the entire page contents has returned. If on the other hand we do not need to do this (by using an IEnumerable<T> rather than an ICollection<T>) we can start processing the page BEFORE the entire thing has been downloaded - allowing for a speedup of the effective render time for the page.

One of the things that slightly concerns me with some of the comments on this page is people noting that if you have a List<T> and you expose this as an IEnumerable<T> that this can (in principle) be cast back to a List<T> and modified - but as soon as I see this I think "that sentiment is certainly true - but if a programmer is willing to forego safe programming practises, is that not his/her fault when it all goes wrong?". Certainly in my code I expect that when I expose an IEnumerable<T> that either myself or any other programmer will never try to cast it back to a List<T> - if they need random access they can use the constructor of List<T> that takes an IEnumerable<T>, but according to the contract that the method gives, it does not say that the IEnumerable<T> is castable to a List<T>, and to assume that it can be cast back is an unsafe assumption - if later I change the implementation to a LinkedList<T> then their code will break, even though the method signature will remain the same.

The question you need to then ask is WHY and WHO you are doing these optimisations for. If you're a component maker who's exposing these properties to a customer, then sure, go right ahead and protect these things with ReadOnlyCollections. If on the other hand you're programming to prevent yourself or your collegages from doing dodgy assumptions, then perhaps you and your collegagues need to have a sit down and discuss whether there is a better way of doing what they're doing.

Remember:

class {
 List<T> _val;
  public IEnumerable<T> {
  get { return _val; }
 }
}

has a computational complexity of 1 and memory overhead of 0.

class {
  List<T> _val;
  public IEnumerable<T> {
    get { return new ReadOnlyCollection(_val); }
  }
}

has a computational complexity and memory overhead of O(_val.Count) - and so you're slowing and bloating your program at the same time.
I always wonder about posts like this.  It's obvious from the post your replying to that I fully understand why IEnumerable<T> doesn't have a Count property or provide random access.  That kinda was the entire point of my post, don't ya think?