I'm currently in learning process of C# and I need an explanation. It's probably logical and simple for someone more experienced, but I thought code should work this way and it doesn't.
I'm trying to print out all Car
objects inside carArray
in my Garage
class with foreach loop using named iterator, but when I pass false value to GetTheCars
method and enter inside else block, nothing happens. Printing array in reverse works just fine. This is the code..
Main method:
static void Main(string[] args)
{
Garage carLot = new Garage();
foreach (Car c in carLot.GetTheCars(false))
{
Console.WriteLine("{0} is going {1} MPH", c.PetName, c.CurrentSpeed);
}
Console.WriteLine();
foreach (Car c in carLot.GetTheCars(true))
{
Console.WriteLine("{0} is going {1} MPH", c.PetName, c.CurrentSpeed);
}
}
Garage class:
class Garage : IEnumerable
{
private Car[] carArray = new Car[4];
public Garage()
{
carArray[0] = new Car("Rusty", 30);
carArray[1] = new Car("Clunker", 55);
carArray[2] = new Car("Zippy", 30);
carArray[3] = new Car("Fred", 30);
}
public IEnumerator GetEnumerator()
{
foreach (Car c in carArray)
{
yield return c;
}
}
public IEnumerable GetTheCars(bool ReturnReversed)
{
if (ReturnReversed)
{
for (int i = carArray.Length; i != 0; i--)
{
yield return carArray[i-1];
}
}
else
{
GetEnumerator();
}
}
In the book example inside the else statement, the same code is written as in GetEnumerator()
method:
Book code difference:
else
{
foreach (Car c in carArray)
{
yield return c;
}
}
I thought I could reuse the code inside the GetEnumerator()
method that was used in previous example of the book, but it prints out nothing. If someone could explain me why I'd be grateful, cheers and thanks in advance!
You're calling GetEnumerator
in the else
block, but that's not going to automatically yield anything. It would be nice if you could have something like:
// This doesn't actually work!
yield all carArray;
... but there's no such construct in C#. You could use:
else
{
using (var iterator in GetEnumerator())
{
while (iterator.MoveNext())
{
yield return iterator.Current;
}
}
}
or skip GetEnumerator
:
else
{
foreach (var var in carArray)
{
yield return car;
}
}
... but obviously that's pretty ugly.
What you could do is separate out the code so that you only use an iterator block (the kind of method with yield return
statements) if you need custom ordering:
// Made return type generic, and improved the name
public IEnumerable<Car> GetTheCars(bool reverseOrder)
{
return reverseOrder ? GetTheCarsReversed() : carArray;
}
private IEnumerable<Car> GetTheCarsReversed()
{
for (int i = carArray.Length; i != 0; i--)
{
yield return carArray[i - 1];
}
}
That does have a disadvantage in terms of returning the array reference directly if you're not asking for the reversed order... the caller could then cast to Car[]
and modify the array. However, that's probably a nuance that don't need to know about just yet.
See more on this question at Stackoverflow