VS2005/c#2.0: enum and user control problems

M

Mike

I'm using VS2005 beta 2.

(1) It looks like "foreach" is looking for an IEnumerable only, and not an
IEnumerator.
That means that class I use in the interation has to have GetEnumerator(),
rather than supporting the IEnumerator protocol (incl. automatically created
generator class using "yield return".) I can define GetEnumerator(), but
this forces me into one implementation (or an ugly class with state that
swiches and calls a sub-enumerator), rather than calling the IEnumerator
directly.
So I can't do:
public IEnumerator listForwards() { yield return 1; yield return 2; }
public IEnumerator listBackwards() { yield return 2; yield return 1; }
foreach ( int i in listForwards()) { ... }
but I'm forced to write:
public IEnumerator GetEnumerator() { return listForwards(); }
to get things to work, boxing me in to what GE() returns.
It's already bad enough that generator functions in c# are restricted to
being enumerators, I hope things aren't even more screwy.
Googling shows that the fomer should work in 2.0. (I know there's an issue
about not having a default GetEnumerator() in the new collections, but
that's a different issue.)

(2) I cannot create an empty winform user control, add it to the toolbox,
and drop it on a form -- either nothing happens, or an error is generated
about not being able to load the control (without other explanation.) The
same exersize works fine (obviously) in VS2003.


Please let me know if I'm misunderstanding things here or have done
something silly, or if the release bits will solve these problems...

thanks,
m
 
M

Mickey Williams [C# MVP]

(1) It looks like "foreach" is looking for an IEnumerable only, and not an
IEnumerator.
That means that class I use in the interation has to have GetEnumerator(),
....

Not really -- this works for me, but maybe I'm missing the point -- just
type the return as IEnumerable:
public class RaceGrid
{
int[] _rg = new int[] { 1, 2 };
public IEnumerable ListForward()
{
for(int i = 0; i < _rg.Length; ++i)
yield return _rg;
}
}

Client-side code looks like:
RaceGrid rg = new RaceGrid();
foreach(int i in rg.ListForward())
{
Console.WriteLine(i);
}
 
?

=?ISO-8859-1?Q?Lasse_V=E5gs=E6ther_Karlsen?=

Mike said:
I'm using VS2005 beta 2.

(1) It looks like "foreach" is looking for an IEnumerable only, and not an
IEnumerator.
That means that class I use in the interation has to have GetEnumerator(),

Simply add a GetEnumerator() method that returns this:

public class SomeClass<T> : IEnumerator<T>, IEnumerable<T>
{
....

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

....
}

(this assumes you're using .NET 2.0 and that the class implements
IEnumerator<T>, if not, just remove <T>).

Of course, doing it this way as opposed to constructing a new enumerator
class wrapping your object means that only one enumerator can be used at
any given time against such an object.
 
M

Mike

Lasse Vågsæther Karlsen said:
Simply add a GetEnumerator() method that returns this:

public class SomeClass<T> : IEnumerator<T>, IEnumerable<T>
{
....

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

The key word there is "simply". The whole issue is that your class may have
multiple enumerators.
(For example, c.EnumInOrder(), c.EnumSorted(), c.EnumWithFilter("foo"),
etc.)
C# does not have Java-style non-static inner classes (which is fine with me
in general) so this forces the use of some other pattern (such as a class
which "switches" or several sub-classes) to get differrent enumerators - all
of which requires more code than necessary. (If it weren't for the fact the
just returning IEnumerable from the generator works, whether it make sense
or not...)
 
M

Mike

Mickey Williams said:
...

Not really -- this works for me, but maybe I'm missing the point -- just
type the return as IEnumerable:

Yes, this seems to work. The point is -- this is, if not a bug, at least a
wart.
The protocol that is encapsulated by IEnumerator (Current, MoveNext()...) is
all that is required for "foreach" to work.
It would makes sense to use IEnumerable as backup if the target for
"foreach" did not support IEnumerator, but it should not require it.

m
public class RaceGrid
{
int[] _rg = new int[] { 1, 2 };
public IEnumerable ListForward()
{
for(int i = 0; i < _rg.Length; ++i)
yield return _rg;
}
}

Client-side code looks like:
RaceGrid rg = new RaceGrid();
foreach(int i in rg.ListForward())
{
Console.WriteLine(i);
}
 
T

Ted Miller

Mike said:
The key word there is "simply". The whole issue is that your class may
have multiple enumerators.
(For example, c.EnumInOrder(), c.EnumSorted(), c.EnumWithFilter("foo"),
etc.)
C# does not have Java-style non-static inner classes (which is fine with
me in general) so this forces the use of some other pattern (such as a
class which "switches" or several sub-classes) to get differrent
enumerators - all of which requires more code than necessary. (If it
weren't for the fact the just returning IEnumerable from the generator
works, whether it make sense or not...)

This is what C#2.0 custom iterators are for -- requires a bare minimum of
code.

class ManyIterators
{
private string[] values;

public IEnumerable<string> GetValues()
{
return this.values;
}

public IEnumerable<string> GetValuesInReverse()
{
for (int i=values.Length-1; i>=0; --i)
{
yield return this.values;
}
}

public IEnumerable<string> GetValuesAndAppend(string tail)
{
foreach (string s in this.values)
{
yield return s + tail;
}
}
}


ManyIterators iter;
foreach (string s in iter.GetValues())
{
//...
}
foreach (string s in iter.GetValuesInReverse())
{
//...
}

etc
 
M

Mike

Ted Miller said:
This is what C#2.0 custom iterators are for -- requires a bare minimum of
code.

Yes, I know.

I was pointing out that IEnumerator should be the required signature for
"foreach" to work - not IEnumerable.
The fact that the auto-generated code for the yeilding function in effect
generates an IEnumerable implementation that points to itself is what makes
this work, but is hardly necessary.

m
class ManyIterators
{
private string[] values;

public IEnumerable<string> GetValues()
{
return this.values;
}

public IEnumerable<string> GetValuesInReverse()
{
for (int i=values.Length-1; i>=0; --i)
{
yield return this.values;
}
}

public IEnumerable<string> GetValuesAndAppend(string tail)
{
foreach (string s in this.values)
{
yield return s + tail;
}
}
}


ManyIterators iter;
foreach (string s in iter.GetValues())
{
//...
}
foreach (string s in iter.GetValuesInReverse())
{
//...
}

etc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top