Why does IEnumeratorT inherit from IDisposable while the non-generic IEnumerator does not?
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
.
Implementing IEnumerator/ IEnumerable with IDispose error
IEnumerator<T>
inherits from IDisposable
, you so have to implement it too and provide a Dispose
method.
IEnumerator<T>
inherits from IEnumerator
, so you have to implement it too and provide a GetEnumerator()
function returning an IEnumerator
.
IEnumerator<T>
defines a property Current
which returns a T
, so you have to implement one.
I guess the confusion arises from the fact that the generic IEnumerable<T>
and IEnumerator<T>
inherit from the non-generic versions (IEnumerable
and IEnumerator
), demanding to implement methods with the same name but different return value types; and that IEnumerator<T>
inherits from IDisposable
while IEnumerator
does not.
So, in the end, your class should look something like
public class AppAnnieImport : IEnumerator<AppLines>, IEnumerable<AppLines>
{
public int code { get; set; }
public DateTime end_date { get; set; }
public string vertical { get; set; }
public string granularity { get; set; }
public string device { get; set; }
public List<AppLines> AppLine { get; set; }
private int position;
//IEnumerator and IEnumerable require these methods.
public IEnumerator<AppLines> GetEnumerator()
{
return (IEnumerator<AppLines>)this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator<AppLines>)this;
}
//IEnumerator
public bool MoveNext()
{
position++;
return (position < AppLine.Count);
}
//IEnumerable
public void Reset()
{ position = 0; }
//IEnumerable
object IEnumerator.Current
{
get { return (AppLine.ToArray())[position] ; }
}
public AppLines Current
{
get { return (AppLine.ToArray())[position] ; }
}
public void Dispose()
{
// do something or not
}
}
making use of explicit interface implementation (you may also want to get rid of the code duplication).
IEnumerator: Is it normal to have an empty Dispose method?
Yes, it is.
IEnumerator<T>
implements IDisposable
in case you make an enumerator that does need to be disposed. Since most enumerators don't need to be disposed, the method will usually be empty.
By the way, you can implement your IEnumerator
more easily by creating an iterator.
Why does the using statement work on IEnumerator and what does it do?
Please, check the following link about foreach statement. It uses try/finally block with Dispose call if it's possible. That's the code which is behind using statement.
Does the non-generic version of IEnumerable support deferred execution?
Yes, it is supported ever since the yield
keyword was. The only difference is that it's more or less IEnumerable<object>
, which might lead to inefficiencies if it has to do boxing. Other than that, it's exactly the same.
Why generic ICollectionT does not inherit some non-generic interface with Count property?
Is it just bad design choice?
Probably the answer is yes.
And to solve this issue in .NET 4.5 MS introduced IReadOnlyCollection<out T>
interface, which is covariant for reference types.
So you can rewrite your code like following
static int? FastCountOrZero(this IEnumerable items)
{
if (items == null)
return 0;
var collection = items as ICollection;
if (collection != null)
return collection.Count;
var roCollection = items as IReadOnlyCollection<object>; // only for reference types
if (roCollection != null)
return roCollection.Count;
var source = items as IQueryable;
if (source != null)
return QueryableEx.Count(source);
return items.Cast<object>().Count();
}
And as last resort you can cast items
to dynamic object and invoke Count
property dynamicly.
if (items.GetType().GetInterface("System.Collections.Generic.ICollection`1") != null)
{
dynamic dynamic = items;
return dynamic.Count;
}
Related Topics
How to Put Text on Progressbar
How to Convert String "07:35" (Hh:Mm) to Timespan
..The Underlying Connection Was Closed: an Unexpected Error Occurred on a Receive
Working with Appdomain.Assemblyresolve Event
C# String Replace with Dictionary
Identifying Nhibernate Proxy Classes
Wpf/Mvvm - How to Handle Double-Click on Treeviewitems in the Viewmodel
How to Set Read Permission on the Private Key File of X.509 Certificate from .Net
Getting Date or Time Only from a Datetime Object
How to Read Image Pixels' Values as Rgb into 2D Array
How to Change Listview Selected Row Backcolor Even When Focus on Another Control
Iapplicationactivationmanager::Activateapplication in C#