Reputation: 2923
I've implemented the GetEnumerator
method for a simple class and was surprised that I couldn't order the enumerator with linq (a call to this.OrderBy(x => x)
is invalid). Can someone please explain what's going on here? Am I doing something wrong or are enumerators only intended to be iterated over?
class Test
{
private Dictionary<int, string> dict
= new Dictionary<int, string>();
public IEnumerator<int> GetEnumerator()
{
return dict.Keys.GetEnumerator();
}
public Test()
{
dict[1] = "test";
dict[2] = "nothing";
}
public IEnumerable<int> SortedKeys
{
get { return this.OrderBy(x => x); } // illegal!
}
public void Print()
{
foreach(var key in this)
Console.WriteLine(dict[key]);
}
}
Upvotes: 3
Views: 787
Reputation: 8894
OrderBy()
is an extension method on IEnumerable<T>
.
Your class does not implement IEnumerable<T>
.
foreach
still works, because it does not require you to implement IEnumerable<T>
; it only requires that there is a method GetEnumerator()
.
So all you need to do is add:
class Test : IEnumerable<int>
and provide the implementation for the non-generic IEnumerable
:
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
Upvotes: 1
Reputation: 157038
You have to implement the interface IEnumerable<int>
in order for the this.OrderBy
to work, how else should it know this
can enumerate int
s?
OrderBy
requires this
to implement IEnumerable<T>
. It doesn't know your GetEnumerator
method is actually an attempt to comply to the interface.
foreach
just requires a GetEnumerator()
method, no interface implementatio needed.
// put in the interface
class Test : IEnumerable<int>
{
private Dictionary<int, string> dict
= new Dictionary<int, string>();
public IEnumerator<int> GetEnumerator()
{
return dict.Keys.GetEnumerator();
}
public Test()
{
dict[1] = "test";
dict[2] = "nothing";
}
public IEnumerable<int> SortedKeys
{
get { return this.OrderBy(x => x); } // illegal!
}
public void Print()
{
foreach (var key in this)
Console.WriteLine(dict[key]);
}
// this one is required according to the interface too
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Upvotes: 7
Reputation: 64943
An enumerator is an iterator. It's just an interface that tells the runtime or custom code on how to move to a next element in some sequence, reset the iteration to the first element again or get current element in the iteration.
That is, an enumerator isn't enumerable. An enumerable can create an enumerator to let other code enumerate the enumeration.
In order to be able to call a LINQ extension method you need the object to be enumerable. Your Test
class doesn't implement IEnumerable<T>
(LINQ extension method signatures look like this: public static IEnumerable<T> Whatever<T>(this IEnumerable<T> someEnumerable)
).
Since I want to apply DRY principle on myself (Don't Repeat Yourself), if you want to know how to implement IEnumerable<T>
you should look at the following Q&A: How do I implement IEnumerable<T>.
Upvotes: 1