views:

65

answers:

2

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?

+16  A: 

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);
Timwi
ah, you beat me to the punch by 10 seconds.. removed my answer and gave you +1. Good answer
Isak Savo
Thanks, didn't suppose it's so easy
Andrzej Nosal
The non-generic `IEnumerable` interface has to be implemented too, I think.
Maciej Hehl
@Maciej: Good point, thanks! Edited.
Timwi
A: 

Try this

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

    public Garage()
    {
        cars.Add(new Car() { CarName = "Car1" });

        cars.Add(new Car() { CarName = "Car2" });

        cars.Add(new Car() { CarName = "Car1" });

        cars.Add(new Car() { CarName = "Car3" });
        cars.Add(new Car() { CarName = "Car4" });
        cars.Add(new Car() { CarName = "Car5" });
    }

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


    #region IEnumerable Members

    public IEnumerator GetEnumerator()
    {
       return cars.GetEnumerator();
    }

    #endregion
}

class Car 
{

    public string CarName { get; set; }

}
saurabh
Better to use the generic interface `IEnumerable<Car>`, this enforces strong typing in the `foreach`.
Jeremy McGee