views:

232

answers:

3

I am new to enumerating collections so forgive if this question sounds silly.

I have an class

public class PersonStuff : IPersonStuff, IEnumerable<User>
    {
        Person person = new Person();
        ...

        IEnumerator<Person> IEnumerable<Person>.GetEnumerator()
        {
            return (person as IEnumerable<Person>).GetEnumerator();
        }
}

As you can see, I am implementing two interfaces in the above: one being IPersonStuff and the other being IEnumerable.

The Person class is a simple getter/setter each type being of string e.g. name, address except dateofbirth which is DateTime.

And in my IPersonStuff I have this:

interface IPersonStuff
    {
        ...
        IEnumerator<Person>  IEnumerable<Person>.GetEnumerator();
    }

Once working, I would like to call it in the following manner (from any class):

    IPersonStuff personStuff = new PersonStuff();

    foreach (Person u in personStuff)
    {
        //this loop should iterate thru the elements.
    }

However, I get the following error:

  • 'IEnumerable<...>.GetEnumerator': explicit interface declaration can only be declared in a class or struct

Basically I want to know how is it possible to call the IEnumerator IEnumerable.GetEnumerator() I have in the PersonStuff class through the IPersonStuff Interface.

+5  A: 

Is IPersonStuff itself collection-like, or just a bunch of properties? If it's not collection-like, there's no need to make it enumerable.

I believe the error is due to using System.Collections.Generic but not System.Collections -- the non-generic IEnumerable is thus not in scope.

I think that if you want IPersonStuff to be enumerable then you can just have IPersonStuff inherit IEnumerable<T> (which in turn inherits IEnumerable). Otherwise, I don't think you'll be able to use foreach over a reference to IPersonStuff.

EDIT Based on further comments and edits, it looks like PersonStuff is intended to be a collection-like data access class for Person, with instantiation managed in monostate fashion.

The monostate instantiation defeats the point of defining an interface IPersonStuff: if you always create it with new PersonStuff() in-line, then (bar bytecode postprocessing) there is no opportunity to use some non-default implementation of the interface.

I would suggest defining some sort of data access context object with properties representing each of your global entity collections, then pass that around in your choice of fashion -- using a parameter or accessor-based singleton is preferable to a monostate. This object may then wrap a database connection, NHibernate session, or similar.

Jeffrey Hantin
+1. "...the non-generic IEnumerable is thus not in scope."
fung
IPersonStuff sets/gets values for the object Person (and uses DB). Person is essentially a getter/setter class. I want to enumerate through items in the Person class.
I mean, I want to enumerate the items that the Person object holds.
btw: IPersonStuff is an Interface for PersonStuff. It just contains the methods for PersonStuff.
In that case, unless something else implements it or you're using it for COM interop, delete IPersonStuff altogether.
Jeffrey Hantin
IPersonStuff is the interface class, I want to call the IEnumerable to be exposed in the Interface IPersonStuff. Is that possible? Amendments made to initial question.
A: 

Instead of doing what you're doing, you probably want to use or inherit from one of the built-in generic collections. For instance:

class PersonStuff : Collection<Person>
{
}

That'll let you iterate over the list of Persons, as well as Add, Insert, Remove, etc. You should only create your own collection type from scratch if none of the built-in collections does what you want.

Kyralessa
My question has been amended slightly. Please can you read my new question and make a suggestion on that. thanks
Your edit doesn't change my recommendation. If you really don't ever want to add, remove, etc. persons, but only want to loop through them, you could certainly implement IEnumerable<Person> instead. You'd still want to use a Collection<Person> internally to hold the Person instances, and return that collection's enumerator in the implementation of GetEnumerator(). ...On the other hand, if you think your enumerator will enumerate the *properties* of a Person instance, then your object model will make no sense to anyone else in the world, and you should rethink it.
Kyralessa
A: 

You're getting the error most probably because like what Jeffrey said you're missing a reference to System.Collections.Generic which has the non-generic IEnumerable. Once you have the correct reference you won't need the cast of (person as IEnumerable).

On whether it should/can be type safe depends on your situation. If all elements of what you're enumerating through are of the same type (i.e. fixed class, interface or subclass) that you should/can use the type safe IEnumerable. But if say maybe you want to enumerate all the properties in Person (which sounds like what you might be attempting) and you're returning diff types then you'll have to use the non-generic IEnumerable.

If you are enumerating through the properties of your class then one nice trick is to use yield return for each property (instead of writing a custom class that implements IEnumerator) in Person.GetEnumerator();

fung
Sorry, yes I have amended the initial question to take care of different types (non generic IEnumerable). Can I call that through the Interface class IPersonStuff?