Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does IEnumerator<T> inherit from IDisposable while the non-generic IEnumerator does not?

I noticed that the generic IEnumerator<T> inherits from IDisposable, but the non-generic interface IEnumerator does not. Why is it designed in this way?

Usually, we use foreach statement to go through a IEnumerator<T> instance. The generated code of foreach actually has try-finally block that invokes Dispose() in finally.

like image 583
Morgan Cheng Avatar asked Oct 24 '08 05:10

Morgan Cheng


1 Answers

Basically it was an oversight. In C# 1.0, foreach never called Dispose 1. With C# 1.2 (introduced in VS2003 - there's no 1.1, bizarrely) foreach began to check in the finally block whether or not the iterator implemented IDisposable - they had to do it that way, because retrospectively making IEnumerator extend IDisposable would have broken everyone's implementation of IEnumerator. If they'd worked out that it's useful for foreach to dispose of iterators in the first place, I'm sure IEnumerator would have extended IDisposable.

When C# 2.0 and .NET 2.0 came out, however, they had a fresh opportunity - new interface, new inheritance. It makes much more sense to have the interface extend IDisposable so that you don't need an execution-time check in the finally block, and now the compiler knows that if the iterator is an IEnumerator<T> it can emit an unconditional call to Dispose.

EDIT: It's incredibly useful for Dispose to be called at the end of iteration (however it ends). It means the iterator can hold on to resources - which makes it feasible for it to, say, read a file line by line. Iterator blocks generate Dispose implementations which make sure that any finally blocks relevant to the "current point of execution" of the iterator are executed when it's disposed - so you can write normal code within the iterator and clean-up should happen appropriately.


1 Looking back at the 1.0 spec, it was already specified. I haven't yet been able to verify this earlier statement that the 1.0 implementation didn't call Dispose.

like image 161
Jon Skeet Avatar answered Sep 28 '22 11:09

Jon Skeet