Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to convert an IEnumerator to a generic IEnumerator?

I am writing a custom ConfigurationElementCollection for a custom ConfigurationHandler in C#.NET 3.5 and I am wanting to expose the IEnumerator as a generic IEnumerator.

What would be the best way to achieve this?

I am currently using the code:

public new IEnumerator<GenericObject> GetEnumerator()
{
  var list = new List();
  var baseEnum = base.GetEnumerator();
  while(baseEnum.MoveNext())
  {
    var obj = baseEnum.Current as GenericObject;
    if (obj != null)
      list.Add(obj);
  }
  return list.GetEnumerator();
}

Cheers

like image 894
zonkflut Avatar asked May 06 '09 06:05

zonkflut


People also ask

What is IEnumerator C sharp?

IEnumerable in C# is an interface that defines one method, GetEnumerator which returns an IEnumerator interface. This allows readonly access to a collection then a collection that implements IEnumerable can be used with a for-each statement.

What is IEnumerator interface?

IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface. This works for readonly access to a collection that implements that IEnumerable can be used with a foreach statement. IEnumerator has two methods MoveNext and Reset. It also has a property called Current.

Where do we use IEnumerator in C#?

Here is the documentation on IEnumerator . They are used to get the values of lists, where the length is not necessarily known ahead of time (even though it could be). The word comes from enumerate , which means "to count off or name one by one".


4 Answers

I don't believe there's anything in the framework, but you could easily write one:

IEnumerator<T> Cast<T>(IEnumerator iterator) {     while (iterator.MoveNext())     {         yield return (T) iterator.Current;     } } 

It's tempting to just call Enumerable.Cast<T> from LINQ and then call GetEnumerator() on the result - but if your class already implements IEnumerable<T> and T is a value type, that acts as a no-op, so the GetEnumerator() call recurses and throws a StackOverflowException. It's safe to use return foo.Cast<T>.GetEnumerator(); when foo is definitely a different object (which doesn't delegate back to this one) but otherwise, you're probably best off using the code above.

like image 72
Jon Skeet Avatar answered Sep 21 '22 00:09

Jon Skeet


IEnumerable<T> already derives from IEnumerable so there's no need to do any conversion. You can simply cast to it...well actually it's implicit no cast necessary.

IEnumerable<T> enumerable = GetGenericFromSomewhere();
IEnumerable sadOldEnumerable = enumerable;
return sadOldEnumerable.GetEnumerator();

Going the other way round isn't much more difficult with LINQ:

var fancyEnumerable = list.OfType<GenericObject>();
return fancyEnumerable.GetEnumerator();
like image 25
Paul Alexander Avatar answered Sep 25 '22 00:09

Paul Alexander


You can use OfType<T> and Cast<T>.

public static IEnumerable Digits()
{
    return new[]{1, 15, 68, 1235, 12390, 1239};
}

var enumerable = Digits().OfType<int>();
foreach (var item in enumerable)
    // var is here an int. Without the OfType<int(), it would be an object
    Console.WriteLine(i);

To get an IEnumerator<T> instead of an IEnumerable<T> you can just make a call to GetEnumerator()

var enumerator = Digits().OfType<int>().GetEnumerator();
like image 32
Svish Avatar answered Sep 25 '22 00:09

Svish


I was running into the same Stack Overflow problem mentioned is some of the comments. In my case it was due to the fact that the GetEnumerator call needed to be to the base.GetEnumerator otherwise you loop within your own GetEnumerator redefinition.

This is the code that was Throwing the Stack Overflow. The use of the foreach statement call the same GetEnumerator function I'm trying to overload:

public new IEnumerator<T> GetEnumerator()
{
    foreach (T type in this)
    {
        yield return type;
    }
}

I've ended up with a simplified version of the original post as you don't need to use a List holder.

public class ElementCollection<T> : ConfigurationElementCollection, IList<T>
    ...
    public new IEnumerator<T> GetEnumerator()
    {
        var baseEnum = base.GetEnumerator();
        while (baseEnum.MoveNext())
        {
            yield return baseEnum.Current as T;
        }
    }
    ...
}
like image 29
VeV Avatar answered Sep 21 '22 00:09

VeV