Hi Guys
NP87 foreach
foreach is used when checks size of the array. In this program it is used without array. Anyone knows please explain the reason.
Cars carLot = new Cars();
foreach (Car c in carLot)
{
…………………
}
Thank you
using System;
using System.Collections;
namespace ObjEnum
{
public class Car
{
// Internal state data.
private int currSpeed;
private int maxSpeed;
private string petName;
// Is the car alive or dead?
bool carIsDead;
// A car has-a radio.
private Radio theMusicBox = new Radio();
public Car()
{
maxSpeed = 100;
}
public Car(string name, int max, int curr)
{
currSpeed = curr;
maxSpeed = max;
petName = name;
}
public void CrankTunes(bool state)
{
// Tell the radio play (or not).
// Delegate request to inner object.
theMusicBox.TurnOn(state);
}
public void SpeedUp(int delta)
{
// If the car is dead, just say so...
if (carIsDead)
{
Console.WriteLine("{0} is out of order....", petName);
}
else // Not dead, speed up.
{
currSpeed += delta;
if (currSpeed >= maxSpeed)
{
Console.WriteLine("{0} has overheated...", petName);
carIsDead = true;
}
else
Console.WriteLine("\tCurrSpeed = {0}", currSpeed);
}
}
// Properties.
public string PetName
{
get { return petName; }
set { petName = value; }
}
public int CurrSpeed
{
get { return currSpeed; }
set { currSpeed = value; }
}
public int MaxSpeed
{
get { return maxSpeed; }
set { maxSpeed = value; }
}
}
// No pun intended!
public class CarDriver
{
public static void
{
Cars carLot = new Cars();
Console.WriteLine("***** Here are the cars in your lot *****");
foreach (Car c in carLot)
{
Console.WriteLine("-> Name: {0}", c.PetName);
Console.WriteLine("-> Max speed: {0}", c.MaxSpeed);
Console.WriteLine();
}
#region Working with raw IEnumerator
/*
// Now ala IEnumerator
IEnumerator itfEnum;
itfEnum = (IEnumerator)carLot;
// Reset the cursor to the beginning.
itfEnum.Reset();
// Advance internal cursor by 1.
itfEnum.MoveNext();
// Cast to a Car and crank some tunes.
object curCar = itfEnum.Current;
((Car)curCar).CrankTunes(true);
*/
#endregion
}
}
public class Cars : IEnumerable // , IEnumerator
{
// This class maintains an array of cars.
private Car[] carArray;
// Current position in array.
// int pos = -1;
public Cars()
{
carArray = new Car[4];
carArray[0] = new Car("FeeFee", 200, 0);
carArray[1] = new Car("Clunker", 90, 0);
carArray[2] = new Car("Zippy", 30, 0);
carArray[3] = new Car("Fred", 30, 0);
}
#region Raw IEnumerator impl
/*
// Implementation of IEnumerator.
public bool MoveNext()
{
if(pos < carArray.Length)
{
pos++;
return true;
}
else
return false;
}
public void Reset()
{
pos = 0;
}
public object Current
{
get { return carArray[pos]; }
}
*/
#endregion
// This must be present in order to let the foreach
// expression to iterate over our array.
// IEnumerable implemtation.
public IEnumerator GetEnumerator()
{
// return (IEnumerator)this;
// Now just get back the IEnumerator from
// the internal array!
return carArray.GetEnumerator();
}
}
public class Radio
{
public void TurnOn(bool on)
{
if (on)
Console.WriteLine("Jamming...");
else
Console.WriteLine("Quiet time...");
}
}
}
/*
***** Here are the cars in your lot *****
-> Name: FeeFee
-> Max speed: 200
-> Name: Clunker
-> Max speed: 90
-> Name: Zippy
-> Max speed: 30
-> Name: Fred
-> Max speed: 30
*/
Posted Apr 12, 2008, 6:54 AM
Thank you for your explanation, Alan
AlanPosted Apr 12, 2008, 6:38 AM
When you cast a double to an int, then a new 'int' object is created. This is because double and int are both value types i.e. the stack variables weeklyBudget and dollars hold the values themselves, not pointers to where they're stored
The double first needs to be truncated as ints can only contain whole numbers. If the resulting value were outside the range of an int, then only the last 32 bits would be used to calculate the int value.
However, when you cast a reference type such as carLot (of type Cars) a new object is not created. Instead the current object is viewed as being of a different (but compatible) type.
As Cars implements IEnumerator, the carLot variable can be cast to IEnumerator and then assigned to the IEnumerator variable, itfEnum. However, notice that you will then only be able to able to access the IEnumerator members which carLot contains, via the itfEnum variable, not its other members.
Posted Apr 11, 2008, 7:20 PM
double weeklyBudget = 47.415;
int dollars = (int)weeklyBudget;
dollars = 47;
When casting a double into integer it truncates numbers after decimal point. This can be explained in such a way.
What is happening when casting an object? How it can be explained? For example:
IEnumerator itfEnum;
itfEnum = (IEnumerator)carLot;
Anyone knows please explain.
AlanPosted Apr 9, 2008, 6:55 PM
Remembering that array indexing starts at 0, the last item of the carArray array is at index carArray.Length - 1.
You only want to increment 'pos', which keeps track of the current position in the enumeration, if pos is currently less than carArray.Length - 1. Otherwise you'll get an array index out of bounds error.
So this is the reason why I corrected that particular line.
Posted Apr 9, 2008, 5:10 PM
In the above program why it is carArray.Length – 1.
if (pos < carArray.Length - 1)
AlanPosted Mar 20, 2008, 11:09 AM
For the viewpoint of using foreach there's no need for the Cars class to implement IEnumerable as long as it contains an 'appropriate' GetEnumerator() method which it does. So the code still works if you remove it.
However, there might be other reasons why you'd want it to 'officially' implement IEnumerable (there are a lot of methods which take an IEnumerable as a parameter) and this may be why the writer of the code left it in.
The 'pos' variable keeps track of the current position in the enumeration and, before the enumeration starts, should be set to the position just before the first element in the sequence. As the first element is at position 0, 'pos' is therefore set initially to -1.
Posted Mar 20, 2008, 8:32 AM
public class Cars : IEnumerable, IEnumerator //** now implements both interfaces
What is the purpose of IEnumerable in above, because without IEnumerable program is executing well.
Also what is meant by int pos = -1; //** uncommented this line
AlanPosted Mar 19, 2008, 8:19 PM
Yes, it is.
Those three members have to be implemented by any class which implements the IEnumerator interface which the Cars class does.
Also the current instance of the Cars class i.e.'this' can be optionally cast to IEnumerator to show that it satisfies the return type of the GetEnumerator method. However, the cast is not essential because Cars is implicitly convertible to IEnumerator and so a simple:
return this;
will also work.
Posted Mar 19, 2008, 5:54 PM
Thank you for your help, Alan.
I wish to know whether in this (return (IEnumerator)this;) expression IEnumerator is representing the following:
bool MoveNext ();
object Current { get;}
void Reset ();
AlanPosted Mar 19, 2008, 3:36 PM
I've marked the changes you need to make with red //** comments. Notice that there's now an extra line of output and also there was a bug in the program which I've corrected.
Sorry, it's no longer color syntax highlighted but I had to paste it into Notepad first to change and then test it.
using System;
using System.Collections;
namespace ObjEnum
{
public class Car
{
// Internal state data.
private int currSpeed;
private int maxSpeed;
private string petName;
// Is the car alive or dead?
bool carIsDead;
// A car has-a radio.
private Radio theMusicBox = new Radio();
public Car()
{
maxSpeed = 100;
}
public Car(string name, int max, int curr)
{
currSpeed = curr;
maxSpeed = max;
petName = name;
}
public void CrankTunes(bool state)
{
// Tell the radio play (or not).
// Delegate request to inner object.
theMusicBox.TurnOn(state);
}
public void SpeedUp(int delta)
{
// If the car is dead, just say so...
if (carIsDead)
{
Console.WriteLine("{0} is out of order....", petName);
}
else // Not dead, speed up.
{
currSpeed += delta;
if (currSpeed >= maxSpeed)
{
Console.WriteLine("{0} has overheated...", petName);
carIsDead = true;
}
else
Console.WriteLine("\tCurrSpeed = {0}", currSpeed);
}
}
// Properties.
public string PetName
{
get { return petName; }
set { petName = value; }
}
public int CurrSpeed
{
get { return currSpeed; }
set { currSpeed = value; }
}
public int MaxSpeed
{
get { return maxSpeed; }
set { maxSpeed = value; }
}
}
// No pun intended!
public class CarDriver
{
public static void Main()
{
Cars carLot = new Cars();
Console.WriteLine("***** Here are the cars in your lot *****");
foreach (Car c in carLot)
{
Console.WriteLine("-> Name: {0}", c.PetName);
Console.WriteLine("-> Max speed: {0}", c.MaxSpeed);
Console.WriteLine();
}
#region Working with raw IEnumerator
//** changed to a single line comment to uncomment the code in the region below
// Now ala IEnumerator
IEnumerator itfEnum;
itfEnum = (IEnumerator)carLot;
// Reset the cursor to the beginning.
itfEnum.Reset();
// Advance internal cursor by 1.
itfEnum.MoveNext();
// Cast to a Car and crank some tunes.
object curCar = itfEnum.Current;
((Car)curCar).CrankTunes(true);
//** changed to a single line comment to uncomment the code in the region above
#endregion
}
}
public class Cars : IEnumerable, IEnumerator //** now implements both interfaces
{
// This class maintains an array of cars.
private Car[] carArray;
// Current position in array.
int pos = -1; //** uncommented this line
public Cars()
{
carArray = new Car[4];
carArray[0] = new Car("FeeFee", 200, 0);
carArray[1] = new Car("Clunker", 90, 0);
carArray[2] = new Car("Zippy", 30, 0);
carArray[3] = new Car("Fred", 30, 0);
}
#region Raw IEnumerator impl
//** changed to a single line comment to uncomment the code in the region below
// Implementation of IEnumerator.
public bool MoveNext()
{
if(pos < carArray.Length - 1) //** changed this line from if(pos < carArray.Length) which was wrong
{
pos++;
return true;
}
else
return false;
}
public void Reset()
{
pos = 0;
}
public object Current
{
get { return carArray[pos]; }
}
//** changed to a single line comment to uncomment the code in the region above
#endregion
// This must be present in order to let the foreach
// expression to iterate over our array.
// IEnumerable implemtation.
public IEnumerator GetEnumerator()
{
return (IEnumerator)this; //** uncommented this line
// Now just get back the IEnumerator from
// the internal array!
//return carArray.GetEnumerator(); //** commented out this line
}
}
public class Radio
{
public void TurnOn(bool on)
{
if (on)
Console.WriteLine("Jamming...");
else
Console.WriteLine("Quiet time...");
}
}
}
/*
***** Here are the cars in your lot *****
-> Name: FeeFee
-> Max speed: 200
-> Name: Clunker
-> Max speed: 90
-> Name: Zippy
-> Max speed: 30
-> Name: Fred
-> Max speed: 30
Jamming... //** extra line of output
*/
Posted Mar 19, 2008, 2:09 PM
In this program, if return (IEnumerator)this; is being activiated what modification has to be done to execute the program. Anyone knows please tell me.
AlanPosted Mar 17, 2008, 8:31 AM
The 'foreach' keyword can be used to iterate over any collection class which implements IEnumerable, not just arrays.
Here 'carLot' is a variable of type Cars which implements IEnumerable and is a custom collection of Car objects.
If you're not interested in doing something with the index of each object in the collection, then it's more convenient to use a foreach loop rather than a for loop and only marginally slower.