27

So I've got a class and a generic List inside of it, but it is private.

class Contacts
{
    List<Contact> contacts;
    ...
}

I want to make the class work as this would do:

foreach(Contact in contacts) .... ;

like this (not working):

Contacts c;
foreach(Contact in c) .... ;

In the example above the Contact class instance c has to yield return every item from contacts(private member of c)

How do I do it? I know it has to be IEnumerable with yield return, but where to declare that?

cspolton
  • 4,495
  • 4
  • 26
  • 34
Ivan Prodanov
  • 34,634
  • 78
  • 176
  • 248

5 Answers5

39

Implement the interface IEnumerable:

class Contacts : IEnumerable<Contact>
{
    List<Contact> contacts;

    #region Implementation of IEnumerable
    public IEnumerator<Contact> GetEnumerator()
    {
        return contacts.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    #endregion
}
LightStriker
  • 19,738
  • 3
  • 23
  • 27
16

Or return an IEnumerator<Contact> by providing a GetEnumerator method:

class Contacts
{
    List<Contact> contacts;

    public IEnumerator<Contact> GetEnumerator()
    {
        foreach (var contact in contacts)
            yield return contact;
    }
}

The foreach looks for GetEnumerator. Have a look here for the language specification details regarding this: https://stackoverflow.com/a/3679993/284240

How to make a Visual C# class usable in a foreach statement

Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • @TimeSchmelter: And how is the foreach going to know that this class implement a GetEnumerator method if it has no interface to declare the implementation contract? – LightStriker Oct 30 '12 at 09:14
  • 2
    @Marc-AndréJutras: The `foreach` looks for `GetEnumerator`. Have a look here for the language specification details: http://stackoverflow.com/a/3679993/284240 – Tim Schmelter Oct 30 '12 at 09:34
  • Interresting. Always been under the impression that the interface was mandatory. Good to know. "The disadvantage of omitting IEnumerable and IEnumerator is that the collection class is no longer interoperable with the foreach statements, or equivalents, of other common language runtime-compatible languages."... Oww... That's a killer. – LightStriker Oct 30 '12 at 09:38
  • This answer is enough if we are using List. – Ronald Abellano Apr 15 '19 at 09:07
6
public class Contacts: IEnumerable
{
     ...... 
    public IEnumerator GetEnumerator()
    {
        return contacts.GetEnumerator();
    }
}

Should do a trick for you.

Tigran
  • 61,654
  • 8
  • 86
  • 123
4
class Program
{
    static void Main(string[] args)
    {
        var list = new Contacts();
        var a = new Contact() { Name = "a" };
        var b = new Contact() { Name = "b" };
        var c = new Contact() { Name = "c" };
        var d = new Contact() { Name = "d" };
        list.ContactList = new List<Contact>();
        list.ContactList.Add(a);
        list.ContactList.Add(b);
        list.ContactList.Add(c);
        list.ContactList.Add(d);

        foreach (var i in list)
        {
            Console.WriteLine(i.Name);
        }
    }
}

class Contacts : IEnumerable<Contact>
{
    public List<Contact> ContactList { get; set; }

    public IEnumerator<Contact> GetEnumerator()
    {
        return ContactList.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ContactList.GetEnumerator();
    }
}

class Contact
{
    public string Name { get; set; }
}
flaugh
  • 1,517
  • 1
  • 10
  • 5
4

How about just extending List<Contact>

If you don't want to extend any other class its a very simple, fast option:

class Contacts :List<Contact>
{   
}
Stephanie
  • 600
  • 13
  • 24
  • 1
    It might not be an answer to the question, as posed, but I believe this answer is seriously underestimated. Extending `List` might very well be the best solution in some cases! :-) – Björn Larsson Dec 07 '18 at 09:37
  • This is a good approach. Tim's answer may be preferable in cases where one seeks to prevent free modification of the list by forcing the caller to interact with exposed methods only. – Anil Jul 29 '23 at 21:36