How to Implement Ienumerable<T>

How do I implement IEnumerable T

If you choose to use a generic collection, such as List<MyObject> instead of ArrayList, you'll find that the List<MyObject> will provide both generic and non-generic enumerators that you can use.

using System.Collections;

class MyObjects : IEnumerable<MyObject>
{
List<MyObject> mylist = new List<MyObject>();

public MyObject this[int index]
{
get { return mylist[index]; }
set { mylist.Insert(index, value); }
}

public IEnumerator<MyObject> GetEnumerator()
{
return mylist.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}

How to implement IEnumerable T ?

A method resolution clause can do the job:

type
TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>, IEnumerable)
public
{ IEnumerable<T> }
function GetEnumeratorGeneric: IEnumerator<T>;
function IEnumerable<T>.GetEnumerator = GetEnumeratorGeneric;

{ IEnumerable }
function GetEnumerator: IEnumerator;
function IEnumerable.GetEnumerator = GetEnumerator;
end;

Your attempt failed, it seems, because neither of your methods was named GetEnumerator. In my code above, one of them is called GetEnumerator and the other one is given a different name. From my experimentation, you have to have exactly one of the implementing methods having the same name as the interface method.

Which is weird. I'd say that this looks like a compiler bug. The behaviour persists even to XE7.

On the other hand, at least you have a way to move forward now.

Update

OK, Stefan's comment below leads me to, belatedly, understand what is really going on. You actually need to satisfy three interface methods here. Clearly we have to provide an implementation for IEnumerable.GetEnumerator, in order to satisfy IEnumerable. But since IEnumerable<T> derives from IEnumerable, then IEnumerable<T> contains two methods, IEnumerable.GetEnumerator and IEnumerable<T>.GetEnumerator. So what you really want to be able to do is something like this:

I'm finding it a little hard to keep track of the clashing names and the generics, so I'm going to offer an alternative example that I think draws out the key point more clearly:

type
IBase = interface
procedure Foo;
end;

IDerived = interface(IBase)
procedure Bar;
end;

TImplementingClass = class(TInterfacedObject, IBase, IDerived)
procedure Proc1;
procedure IBase.Foo = Proc1;

procedure Proc2;
procedure IDerived.Bar = Proc2;
end;

Now, note that the use of interface inheritance means that IDerived contains two methods, Foo and Bar.

The code above won't compile. The compiler says:

E2291 Missing implementation of interface method IBase.Foo

Which of course seems odd because surely the method resolution clause dealt with that. Well, no, the method resolution dealt with the Foo declared in IBase, but not the one in IDerived that was inherited.

In the example above we can solve the problem quite easily:

TImplementingClass = class(TInterfacedObject, IBase, IDerived)
procedure Proc1;
procedure IBase.Foo = Proc1;
procedure IDerived.Foo = Proc1;

procedure Proc2;
procedure IDerived.Bar = Proc2;
end;

This is enough to make the compiler happy. We've now provided implementations for all three methods that need to be implemented.

Unfortunately you cannot do this with IEnumerable<T> because the inherited method has the same name as the new method introduced by IEnumerable<T>.

Thanks again to Stefan for leading me to enlightenment.

How do I implement IEnumerable T ?

In order to be able to use an instance of a type as an IEnumerable<T>, the type must implement IEnumerable<T>. You indicate that you want to do this by adding : IEnumerable<T> after the class name in the declaration:

public class Container<T> : IEnumerable<T>
// ...

When you do that, you will get compiler errors complaining that you haven't implemented all the required members. Your IDE should be able to auto-generate stubs for them, but this is what you'll have to do:

public class Container<T> : IEnumerable<T>
{
// forward the non-generic version to the generic version
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

// implement GetEnumerator from the generic interface
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
}

Now, the most common way to implement your own IEnumerable<T> is to wrap a built-in one, e.g. a List<T> or an array. If that's what you're doing, you can just forward the GetEnumerator() call to the inner instance and be done.

If you want to do something more sophisticated, you can e.g. build your iteration protocol using the yield return construct:

public IEnumerator<T> GetEnumerator()
{
// do some work
// then return the first element:
yield return default(T); // yeah, you probably have an actual value

// do some more work
// return another value:
yield return default(T);

// if you want to abort the iteration prematurely
// e.g. based on some condition
// you can
yield break;
}

implement ienumerable with ienumerable T

The need is simply because of how the interfaces are implemented. In .NET 1.1, there were no generics, so IEnumerable has no generic support and only exposes object. This introduces boxing (and is why the compiler also supports a pattern-based implementation for foreach, independent of IEnumerable). In C# 2, we got IEnumerable<T>. It is useful to consider all typed iterations as also being untyped, hence:

IEnumerable<T> : IEnumerable

where IEnumerable<T> re-declares GetEnumerator as with the generic type. However, since these are now different methods with different signatures, it needs 2 different implementations.

Implementing IEnumerable T interface

What does this.Content.GetEnumerator(); and this.GetEnumerator(); do here?

First method returns generic IEnumerator<T>, second one returns non-generic variant using explicit implementation of IEnumerable interface (actually, IEnumerator<T> inherits non-generic IEnumerator, as you can see in docs)

Current property is declared in generic IEnumerator<T>, MoveNext() and Reset() are declared in non-generic IEnumerator.

IEnumerable exposes IEnumerator struct to iterate through collection, this a reason of separating the methods.

First versions of .NET have only non-generic collections, generics were introduced later, so there is both generic and non-generic variants of IEnumerable and IEnumerator.

You can refer to sources to see, how it's implemented internally for generic List<T>.

internal Enumerator(List<T> list) {
this.list = list;
index = 0;
version = list._version;
current = default(T);
}

Actually the list instance is passed to Enumerator constructor and MoveNext(), Reset() and Current are working over the passed instance

How to implement IEnumerable T with GetEnumerator()?

You're missing IEnumerator IEnumerable.GetEnumerator():

public class Simulation : IEnumerable<string>
{
private IEnumerable<string> Events()
{
yield return "a";
yield return "b";
}

public IEnumerator<string> GetEnumerator()
{
return Events().GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

Implementing IEnumerable to my object

What you need to do is:

(1) Make your class implement IEnumerable<T> where T is the type of the enumerated items. (In your case, it looks like it would be LLNode).

(2) Write a public IEnumerator<T> GetEnumerator. Implement it using the "yield" keyword.

(3) Add a IEnumerator IEnumerable.GetEnumerator() method and just return GetEnumerator().

The following code should make this clear. Where I have <int>, you should put <LLNode>, assuming that is the correct type.

using System;
using System.Collections;
using System.Collections.Generic;

namespace Demo
{
internal class Program
{
private static void Main()
{
var test = new MyDemo();

foreach (int item in test)
{
Console.WriteLine(item);
}
}
}

public class MyDemo: IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
// Your implementation of this method will iterate over your nodes
// and use "yield return" to return each one in turn.

for (int i = 10; i <= 20; ++i)
{
yield return i;
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

I would have modified your code to do it properly, but the code you posted won't compile.

[EDIT]

Now you've updated your code, I can see that you want to enumerate the values. Here's the completed code:

using System;
using System.Collections;
using System.Collections.Generic;

namespace Demo
{
internal class Program
{
private LL myList = new LL();

private static void Main()
{
var gogo = new Program();
}

public Program()
{
myList.Add("test");
myList.Add("test1");

foreach (var item in myList) // This now works.
Console.WriteLine(item);

Console.Read();
}
}

internal class LL: IEnumerable<string>
{
private LLNode first;

public void Add(string s)
{
if (this.first == null)
this.first = new LLNode
{
Value = s
};
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;

node.Next = new LLNode
{
Value = s
};
}
}

public IEnumerator<string> GetEnumerator()
{
for (var node = first; node != null; node = node.Next)
{
yield return node.Value;
}
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

private class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}
}
}

Troubles implementing IEnumerable T

Since IEnumerable<T> implements IEnumerable you need to implement this interface as well in your class which has the non-generic version of the GetEnumerator method. To avoid conflicts you could implement it explicitly:

IEnumerator IEnumerable.GetEnumerator()
{
// call the generic version of the method
return this.GetEnumerator();
}

public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < Count; i++)
yield return _array[i];
}

Implement IEnumerable T in C# on linked list built from scratch

Since you have created a custom collection, you won't be able to just use an existing IEnumerator implementation. You'll need to create one:

public class LinkedListEnumerator<T> : IEnumerator<T>
{
public LinkedListEnumerator(LinkedList<T> collection)
{
}
...
}

I'm passing the collection to be enumerated into the constructor. Other ways could work but that seemed the easiest way to get it there. Now your IEnumerable<T> implementation is:

    public IEnumerator<T> GetEnumerator()
{
return new LinkedListEnumerator<T>(this);
}

IEnumerator IEnumerable.GetEnumerator()
{
return new LinkedListEnumerator<T>(this);
}

Actual IEnumerator implementation left as an exercise.



Related Topics



Leave a reply



Submit