Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload indexer to have foreach'able class

I tried to do something like this but this doesn't work:

    class Garage
    {
        private List<Car> cars = new List<Car>();

        public Car this[int i]
        {
            get { return cars[i]; }
        }
         //...
    }

       Garage g =  new Garage();
       //get CS1579 - no GetEnumerator definition
       foreach (Car c in g)
       {
           //...
       }

As MSDN says indexers can be overloaded, so I decided to ask experts here. How to overload indexers to cooperate with foreach loop?

like image 435
nan Avatar asked Sep 22 '10 12:09

nan


2 Answers

foreach has nothing to do with indexers. You need to declare a GetEnumerator method that returns an enumerator for the collection. (While you’re at it, it may be wise to implement the IEnumerable<Car> interface as well, which provides this method.) In your particular case, you can do it easily like this:

class Garage : IEnumerable<Car>
{
    private List<Car> cars = new List<Car>();

    public Car this[int i]
    {
        get { return cars[i]; }
    }

    // For IEnumerable<Car>
    public IEnumerator<Car> GetEnumerator() { return cars.GetEnumerator(); }

    // For IEnumerable
    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}

A huge benefit of implementing the IEnumerable<Car> interface is that you can use all the LINQ extension methods, e.g. Where and Select, for example:

var redCars = myGarage.Where(car => car.Color == CarColor.Red);
like image 193
Timwi Avatar answered Sep 23 '22 08:09

Timwi


You can also make your cars private, and add a public or internal property, because tomorrow in your garage you will have Employees and Tools and so on, so your enumerate will make no sens. So with the followings you have no more code to provide :

private List<Car> m_Cars=new List<Car>();
private List<Employee> m_Employees=new List<Employee>();
public  List<Car> Cars { get { return m_Cars; } }
internal List<Employee> Employees { get { return m_Employees; } }

So you can use foreach, on cars, employees like this:

var redCars = myGarage.Cars.Where(car => car.Color == CarColor.Red);
var Employees1 = myGarage.Employees.Where(e => e.Name == 'xxx');
like image 30
bruno leclerc Avatar answered Sep 21 '22 08:09

bruno leclerc