Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should you use IEnumerable and GetEnumerator?

Tags:

c#

.net

In many of our projects I have seen a few custom collection / or container classes that hold a some sort of generic collection, e.g. a List(of T) class.

They usually have a GetXXX method that returns a IEnumerable of whatever type the custom collection class uses so the internal collection can be iterated around using a foreach loop.

e.g.

public IEnumerable<UploadState> GetStates
{
    get
    {
        return new List<UploadState>(m_states);
    }
}

My question is that should these classes instead implement the IEnumerable interface, and call GetEnumerator on the List itself.

Is there a preferred way, or is it up to the developer?

like image 439
bobbo Avatar asked Mar 23 '12 10:03

bobbo


3 Answers

If your class is a custom collection class then yes, it should implement IEnumerable<T>. In this case a public property for the inner list would be redundant. Imagine a simple class:

public class People : IEnumerable<Person>
{
    List<Person> persons = new List<Person>();

    public IEnumerator<Person> GetEnumerator()
    {
        return persons.GetEnumerator();
    }
}

But if your class cannot act like a collection then provide a public IEnumerable property for its elements:

public class Flight
{
    List<Person> passengers = new List<Person>();

    public IEnumerable<Person> Passengers
    {
        get { return passengers; }
    }
}

Anyway, it's always up to the developer to choose the right design.

like image 138
Balazs Tihanyi Avatar answered Oct 30 '22 07:10

Balazs Tihanyi


I would do it that way:

public IEnumerable<UploadState> GetStates
{
    get
    {
        foreach (var state in m_states) { 
            yield return state; 
        }
    }
}

It is cleaner, your users don't get a list where they shouldn't (they could cast it to a List<T>after all) and you don't need to create a List<T>object.

EDIT: Misunderstood the question. I think if the class is meant to be a collection, it should implement IEnumerable<T>.

like image 45
Botz3000 Avatar answered Oct 30 '22 07:10

Botz3000


Consider that in your code example a new list created. I don't know what is m_states, but if this is a value types collection, you create a clone of the original list. In this way the returning list can be manipulated form the caller Add/Remove/Update elements. without affectiing original data.

If m_states are reference types, this still creates a new list which can be again manipulated by the caller Add/Remove/ No update elements (it's a reference!) without affecting original data.

What about IEnumerable<T>, its just a way to make a returning type generic, and not make strong coupling to List<T> type.

like image 25
Tigran Avatar answered Oct 30 '22 06:10

Tigran