Compiler error with foreach?

  • Thread starter Thread starter Flinchvoid
  • Start date Start date
F

Flinchvoid

Interesting little problem; go easy on me because I'm just a humble
scripter turned c# developer.

I've a class UserList which I auto-generated with a python script, it
extends CollectionBase and has the usual methods: this[int index],
Add, Insert, Remove and Contains. There are no differences between
this class and the other generated classes I'm using other than the
type of the contained object. The other classes can be foreach'ed
quite happily.

I knocked up a quick console app to test an aspect of this system. I
can iterate the members of the list with an integer index, but not
with a foreach. The method called inside the loop, GetName, does not
alter the underlying object, it just returns a formatted string. Can
anybody shed any light on this peculiar quirk?

// this works

UserList l = dataprovider.GetLocalUsers();

int c = l.Count;

while(c-- > 0){
User u = l[c];
Console.WriteLine(u.GetName(User.NameFormat.InitialSurname));
}


// this causes a compiler error

// foreach(User u in l)
// {
// Console.WriteLine(u.GetName(u.NameFormat.InitialSurname));
// }
 
Flinchvoid said:
Interesting little problem; go easy on me because I'm just a humble
scripter turned c# developer.
<snip>

Does your user list collection class implement IEnumerable ?
 
Flinchvoid said:
I've a class UserList which I auto-generated with a python script, it
extends CollectionBase and has the usual methods: this[int index],
Add, Insert, Remove and Contains. There are no differences between
this class and the other generated classes I'm using other than the
type of the contained object. The other classes can be foreach'ed
quite happily.
You must implement the IEnumerable interface to enable foreach to
enumerate the collection.

Anders Norås
http://dotnetjunkies.com/weblog/anoras/
 
extending CollectionBase isn't enough - you need to implement
GetEnumerator - see MSDN on foreach
 
Okay, there seems to be a concensus here, but I have *other* classes
built in exactly the same way which do use foreach without any
problems.

None of the other collection classes I'm using are any different.
Another test I've run (and just re-run to make sure I'm not
hallucinating) contains the following snippet

EnquirySummaryList l = dp.SearchEnquiryDetails();

foreach(EnquirySummary e in l)
{
Console.WriteLine(e.EnquiryName);
}


EnquirySummaryList is /exactly/ the same as UserList other than the
contained type, and yet it enumerates with foreach. What am I missing?
 
What is the compiler error you get?

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

Interesting little problem; go easy on me because I'm just a humble
scripter turned c# developer.

I've a class UserList which I auto-generated with a python script, it
extends CollectionBase and has the usual methods: this[int index],
Add, Insert, Remove and Contains. There are no differences between
this class and the other generated classes I'm using other than the
type of the contained object. The other classes can be foreach'ed
quite happily.

I knocked up a quick console app to test an aspect of this system. I
can iterate the members of the list with an integer index, but not
with a foreach. The method called inside the loop, GetName, does not
alter the underlying object, it just returns a formatted string. Can
anybody shed any light on this peculiar quirk?

// this works

UserList l = dataprovider.GetLocalUsers();

int c = l.Count;

while(c-- > 0){
User u = l[c];
Console.WriteLine(u.GetName(User.NameFormat.InitialSurname));
}


// this causes a compiler error

// foreach(User u in l)
// {
// Console.WriteLine(u.GetName(u.NameFormat.InitialSurname));
// }

--
No virus found in this incoming message.
Checked by AVG Anti-Virus.
Version: 7.0.300 / Virus Database: 265.7.1 - Release Date: 19/01/2005



[microsoft.public.dotnet.languages.csharp]
 
Drat it, I've found it when trying to reproduce the bug for you: I was
trying to access the NameFormat enum in an instance of User rather than
through the class User. VS.net just borked instead of warning me.

I feel better now that logic has been restored.
Thanks to those who took two minutes to puzzle over my ineptitude.
 
Anders Norås said:
Flinchvoid said:
I've a class UserList which I auto-generated with a python script, it
extends CollectionBase and has the usual methods: this[int index],
Add, Insert, Remove and Contains. There are no differences between
this class and the other generated classes I'm using other than the
type of the contained object. The other classes can be foreach'ed
quite happily.
You must implement the IEnumerable interface to enable foreach to
enumerate the collection.

Not necessarily. Here's an example which doesn't:

using System;
using System.Collections;

class Foo
{
ArrayList list = new ArrayList();

internal int Count
{
get
{
return list.Count;
}
}

internal string this[int i]
{
get
{
return (string)list;
}
}

internal void Add (string x)
{
list.Add(x);
}

public PseudoEnumerator GetEnumerator()
{
return new PseudoEnumerator(this);
}
}

class PseudoEnumerator
{
int current = -1;
Foo foo;

internal PseudoEnumerator (Foo foo)
{
this.foo = foo;
}

public bool MoveNext()
{
current++;
return current < foo.Count;
}

public string Current
{
get
{
return foo[current];
}
}
}

class Test
{
static void Main()
{
Foo f = new Foo();
f.Add ("Hello");
f.Add ("there.");
f.Add ("No");
f.Add ("IEnumerator");
f.Add ("here...");

foreach (string x in f)
{
Console.WriteLine (x);
}
}
}

See the C# language spec for more details.
 
You must implement the IEnumerable interface to enable foreach to
Not necessarily. Here's an example which doesn't:

Very interesting but Iam wondering why this works with foreach/IEnumerable
but not with using/IDisposable.
 
cody said:
Very interesting but Iam wondering why this works with foreach/IEnumerable
but not with using/IDisposable.

Well, because the language specification says it does :)

The reason it's there is to allow people to implement a strongly-typed
enumerator - there's no equivalent need with IDisposable.
 
Back
Top