I'm working in C# with the latest build of Unity3D and MonoDevelop (I believe C# version 6 is currently used in Unity but I may be wrong).
My current situation is, I have a wrapper class for a 2D array and I'd like to be able to iterate over it with a foreach like I would over a regular 2D array.
public class CoordArray<T> : IEnumerable<T> {
// ... some other members
private T[,] arr;
public CoordArray(int width, int height) {
// ... other intialization
arr = new T[height, width];
}
public IEnumerator<T> GetEnumerator() {
return arr.GetEnumerator();
}
...
}
public class Foo {
public void Bar() {
CoordArray<Poop> array = new CoordArray<Poop>(23,213);
foreach(Poop p in array) DoSomething(p);
}
}
This GetEnumerator() method, however, throws the following error in Unity:
Cannot implicitly convert type System.Collections.IEnumerator to System.Collections.Generic.IEnumerator<T>. An explicit conversion exists (are you missing a cast?)
I've found a few solutions to similar problems on this site and I've tried:
public IEnumerator<T> GetEnumerator() {
return ((IEnumerable<T>) arr).GetEnumerator();
}
but this again gives me an error:
Cannot convert type T[,] to System.Collections.Generic.IEnumerable<T>
I've also tried:
public IEnumerator<T> GetEnumerator() {
return (IEnumerator<T>) arr.GetEnumerator();
}
,
public IEnumerator<T> GetEnumerator() {
return arr.Cast<T>().GetEnumerator();
}
and:
public IEnumerator<T> GetEnumerator() {
foreach (T element in arr) yield return element;
}
but these all throw the following error:
CoordArray<T> does not implement interface member System.Collections.IEnumerable.GetEnumerator() and the best implementing candidate CoordArray<T>.GetEnumerator() return type System.Collections.Generic.IEnumerator<T> does not match interface member return type System.Collections.IEnumerator
and if I try:
public IEnumerator GetEnumerator() {
return arr.GetEnumerator();
}
the exact opposite error is thrown:
CoordArray<T> does not implement interface member System.Collections.Generic.IEnumerable<T>.GetEnumerator() and the best implementing candidate CoordArray<T>.GetEnumerator() return type System.Collections.IEnumerator does not match interface member return type System.Collections.Generic.IEnumerator<T>
and (quite obviously) it won't let me implement IEnumerator GetEnumerator() and IEnumerator<T> GetEnumerator() simultaneously.
Is there a way to get a generic iterator from a generic array?
The problem is that 2d array only "implements" the non generic IEnumerable. But you could use Cast method to get IEnumerable<T> and then get the IEnumerator<T> from it:
public IEnumerator<T> GetEnumerator()
{
return arr.Cast<T>().GetEnumerator();
}
Make sure you have included
using System.Linq;
If for some reason Cast method is not available, then I guess at least you can use C# iterator method (available since 2.0):
public IEnumerator<T> GetEnumerator()
{
foreach (T element in arr)
yield return element;
}
Update: The new compiler error you are getting is different. The above solves the implementation of the generic IEnumerable<T>.GetEnumerator() method which I think is the target of your question. But since IEnumerable<T> inherits IEnumerable, you also need to implement the non generic GetEnumerator method in your class as well (I was assuming you already did that). It needs to be implemented explicitly, so add the following to your class:
IEnumerator IEnumerable.GetEnumerator()
{
return arr.GetEnumerator();
}
Would something like this suit your needs?
public class CoordArray<T> : IEnumerable<T>
{
// ... some other members
private T[,] arr;
public CoordArray(int width, int height)
{
// ... other intialization
arr = new T[height, width];
}
private IEnumerable<T> ArrAsEnumerableT
{
get
{
foreach (var elmt in arr)
yield return elmt;
}
}
public IEnumerator<T> GetEnumerator()
{
return ArrAsEnumerableT.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ArrAsEnumerableT.GetEnumerator();
}
}
Related
I'm not used to write C# code, only Java and Python.
Now I found some code example for an algorithm which is only available in C#.
There is one structure I don't understand, it is the Enumerator.
HashSet<Node>.Enumerator enumerator = hashSet.GetEnumerator();
enumerator.MoveNext();
Item next = enumerator.Current;
So Item is the data type stored in the HashSet hashSet. Is this equal to a for-loop iterating over a HashSet or how else can that be translated into python or java?
GetEnumerator() methods are presented in some data structures in C# such as List, Set, etc. It enables doing iteration through. Actually, foreach internally makes use of it.
foreach statement is to iterate through the elements of certain data structures. A foreach can be used when all of the following conditions hold:
The data structure implements either IEnumerable(which is to
satisfy legacy codes before generics) or IEnumerable<T> for some
type T.
You do not need to know the locations in the data structure of the
individual elements.
For example, the string class implements both IEnumerable and IEnumerable<Char>.
The IEnumerable<T> interface implies the data structure requires two methods:
public IEnumerator<T> GetEnumerator()
IEnumerator IEnumerable.GetEnumerator()
The latter method is required only because IEnumerable<T> is a subtype of IEnumerable, and that interface requires a GetEnumerator method that returns a non-generic IEnumerator. Both of these methods should return the same object; hence, because IEnumerator<T> is also a subtype of IEnumerator, this method can simply call the first method:
System.Collections.IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
As you can see, the IEnumerable.GetEnumerator() method returns a reference to another interface named System.Collections.IEnumerator. This interface provides the infrastructure to allow the caller to traverse the internal objects contained by the IEnumerable-compatible container:
public interface IEnumerator
{
bool MoveNext (); // Advance the internal position of the cursor.
object Current { get;} // Get the current item (read-only property).
void Reset (); // Reset the cursor before the first member.
}
Let's exemplify it.
public class PowersOfThree : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
return new PowersOfThreeEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
internal class PowersOfThreeEnumerator : IEnumerator<int>
{
private int index = 0;
public int Current
{
get { return (int)System.Math.Pow(3, index); }
}
object System.Collections.IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
index++;
if (index > 10)
return false;
else
return true;
}
public void Reset()
{
index = 0;
}
public void Dispose()
{
}
}
public class Test
{
public static void Main(string[] str)
{
var p2 = new PowersOfThree();
foreach (int p in p2)
{
System.Console.WriteLine(p);
}
}
}
Current method returns the same element until MoveNext method is called. The initial index is 0 each MoveNext method increments the index from 1 to 10, inclusively, then it returns false. When the enumerator is at this position, subsequent calls to MoveNext also return false.
Do you see that what happened to Current when MoveNext returned false? Can you set Current to the first element of the collection again?
If you don't reinstantiate new enumerator, no.
I write a generic class that implement IEnumerable<T>:
public class EnumerableObject<T> : IEnumerable<T>
{
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
...
}
public IEnumerator GetEnumerator()
{
...
}
}
So i can iterate over object of this class with foreach but if i change type of foreach variable, Compiler not give me a error and i can write this code without compiler error:
foreach (string item in new EnumerableObject<int>())
{
....
}
But if i iterate over a generic list i got a compiler error:
foreach (string item in new List<int>())
{
...
}
Cannot convert type 'int' to 'string'
I think List<T> class condition is like my class EnumerableObject but why i not get a compiler error in my case?
What happens is that because your non-generic GetEnumerator method is public, it is the one implicitly being used be the foreach statement. Thus, it effectively returns a non-generic IEnumerator, allowing you to write foreach (string item in new EnumerableObject<int>()), which will explode at run-time.
If you make the non-generic GetEnumerator method private, you'll see the compile time warning. You should actually be doing it the other way around:
public class EnumerableObject<T> : IEnumerable<T>
{
public IEnumerator<T> GetEnumerator()
{
// Implement.
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
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]);
}
}
You have to implement the interface IEnumerable<int> in order for the this.OrderBy to work, how else should it know this can enumerate ints?
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();
}
}
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>.
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();
}
I assume the following sample gives a best practice that we should follow when we implement the IEnumerable interface.
https://learn.microsoft.com/en-us/dotnet/api/system.collections.ienumerator.movenext
Here is the question:
Why should we provide two version of Current method?
When the version ONE (object IEnumerator.Current) is used?
When the version TWO (public Person Current ) is used?
How to use PeopleEnum in the foreach statement. // updated
public class PeopleEnum : IEnumerator
{
public Person[] _people;
// Enumerators are positioned before the first element
// until the first MoveNext() call.
int position = -1;
public PeopleEnum(Person[] list)
{
_people = list;
}
public bool MoveNext()
{
position++;
return (position < _people.Length);
}
public void Reset()
{
position = -1;
}
// explicit interface implementation
object IEnumerator.Current /// **version ONE**
{
get
{
return Current;
}
}
public Person Current /// **version TWO**
{
get
{
try
{
return _people[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
}
The IEnumerator.Current is an explicit interface implementation.
You can only use it if you cast the iterator to an IEnumerator (which is what the framework does with foreach). In other cases, the second version will be used.
You will see that it returns object and actually uses the other implementation which returns a Person.
The second implementation is not required per se by the interface, but is there as a convenience and in order to return the expected type instead of object.
Long-form implementation of IEnumerator is no longer necessary:
public class PeopleEnum : IEnumerable
{
public Person[] _people;
public PeopleEnum(Person[] list)
{
_people = list;
}
public IEnumerator GetEnumerator()
{
foreach (Person person in _people)
yield return person;
}
}
And to further bring it into the 21st century, don't use the non-generic IEnumerable:
public class PeopleEnum : IEnumerable<Person>
{
public Person[] _people;
public PeopleEnum(Person[] list)
{
_people = list;
}
public IEnumerator<Person> GetEnumerator()
{
foreach (Person person in _people)
yield return person;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
I suspect the reason is that this code example was derived from an example class implementing IEnumerator<T> - if the example class PeopleEnum implemented IEnumerator<T> this approach would be required: IEnumerator<T> inherits IEnumerator so you have to implement both interfaces when implementing IEnumerator<T>.
The implementation of the non-generic IEnumerator requires Current to return object - the strongly typed IEnumerator<T> on the other hand requires Current to return an instance of type T - using explicit and direct interface implementation is the only way to fulfill both requirements.
It is there for convenience, eg. using the PeopleEnum.Current in a typesafe way in a while(p.MoveNext()) loop, not explicitly doing a foreach enumeration.
But the only thing you need to do is implement the interface, you could do it implicitly if you wish, however is there a reason for it? If I wanted to use MovePrevious on the class? Would it be cool if I should cast(unbox) the object to Person?
If you think the class could be extended with more manipulation methods the Person Current is a cool thing.
Version two isnt part of the interface. You have to satisfy the interface requirements.
Can someone share a simple example of using the foreach keyword with custom objects?
Given the tags, I assume you mean in .NET - and I'll choose to talk about C#, as that's what I know about.
The foreach statement (usually) uses IEnumerable and IEnumerator or their generic cousins. A statement of the form:
foreach (Foo element in source)
{
// Body
}
where source implements IEnumerable<Foo> is roughly equivalent to:
using (IEnumerator<Foo> iterator = source.GetEnumerator())
{
Foo element;
while (iterator.MoveNext())
{
element = iterator.Current;
// Body
}
}
Note that the IEnumerator<Foo> is disposed at the end, however the statement exits. This is important for iterator blocks.
To implement IEnumerable<T> or IEnumerator<T> yourself, the easiest way is to use an iterator block. Rather than write all the details here, it's probably best to just refer you to chapter 6 of C# in Depth, which is a free download. The whole of chapter 6 is on iterators. I have another couple of articles on my C# in Depth site, too:
Iterators, iterator blocks and data pipelines
Iterator block implementation details
As a quick example though:
public IEnumerable<int> EvenNumbers0To10()
{
for (int i=0; i <= 10; i += 2)
{
yield return i;
}
}
// Later
foreach (int x in EvenNumbers0To10())
{
Console.WriteLine(x); // 0, 2, 4, 6, 8, 10
}
To implement IEnumerable<T> for a type, you can do something like:
public class Foo : IEnumerable<string>
{
public IEnumerator<string> GetEnumerator()
{
yield return "x";
yield return "y";
}
// Explicit interface implementation for nongeneric interface
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator(); // Just return the generic version
}
}
(I assume C# here)
If you have a list of custom objects you can just use the foreach in the same way as you do with any other object:
List<MyObject> myObjects = // something
foreach(MyObject myObject in myObjects)
{
// Do something nifty here
}
If you want to create your own container you can use the yield keyword (from .Net 2.0 and upwards I believe) together with the IEnumerable interface.
class MyContainer : IEnumerable<int>
{
private int max = 0;
public MyContainer(int max)
{
this.max = max;
}
public IEnumerator<int> GetEnumerator()
{
for(int i = 0; i < max; ++i)
yield return i;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
And then use it with foreach:
MyContainer myContainer = new MyContainer(10);
foreach(int i in myContainer)
Console.WriteLine(i);
From MSDN Reference:
The foreach statement is not limited to IEnumerable types and can be applied to an instance of any type that satisfies the following conditions:
has the public parameterless GetEnumerator method whose return type is either class, struct, or interface type,
the return type of the GetEnumerator method has the public Current property and the public parameterless MoveNext method whose return type is Boolean.
If you declare those methods, you can use foreach keyword without IEnumerable overhead. To verify this, take this code snipped and see that it produces no compile-time error:
class Item
{
public Item Current { get; set; }
public bool MoveNext()
{
return false;
}
}
class Foreachable
{
Item[] items;
int index;
public Item GetEnumerator()
{
return items[index];
}
}
Foreachable foreachable = new Foreachable();
foreach (Item item in foreachable)
{
}