Jet Jaguar

I am either not understanding how the IS operator works or how the FOREACH loop works.

I found some C# code that creates 1 object of 4 different derived classes (see code below). Those 4 objects are assigned to variables of an array of the "base class" type. A FOREACH is used to iterate the array. The FOREACH variable is the "base class" type also.

In the FOREACH loop, the IS operator is used to find the object that is specifically one of the four derived types. Here is my question... Since the FOREACH variable is a "base class" type how can the IS ever evaluate to true since the type it is being compared to is a "derived class" type

What am I missing

Given: Class Employee - An abstract class.

Given: Classes SalariedEmployee, HourlyEmployee and CommissionEmployee that inherit from Class Employee.

Given: Class BasePlusCommissionEmployee that inherits from CommissionEmployee.

// create derived class objects
SalariedEmployee salariedEmployee =
new SalariedEmployee( "John", "Smith", "111-11-1111", 800.00M );
HourlyEmployee hourlyEmployee =
new HourlyEmployee( "Karen", "Price",
"222-22-2222", 16.75M, 40.0M );
CommissionEmployee commissionEmployee =
new CommissionEmployee( "Sue", "Jones",
"333-33-3333", 10000.00M, .06M );
BasePlusCommissionEmployee basePlusCommissionEmployee =
new BasePlusCommissionEmployee( "Bob", "Lewis",
"444-44-4444", 5000.00M, .04M, 300.00M );


// create four-element Employee array
Employee[] employees = new Employee[ 4 ];

// initialize array with Employees of derived types
employees[ 0 ] = salariedEmployee;
employees[ 1 ] = hourlyEmployee;
employees[ 2 ] = commissionEmployee;
employees[ 3 ] = basePlusCommissionEmployee;

// generically process each element in array employees
foreach ( Employee currentEmployee in employees )
{
Console.WriteLine( currentEmployee ); // invokes ToString

// determine whether element is a BasePlusCommissionEmployee
if ( currentEmployee is BasePlusCommissionEmployee )
{
// downcast Employee reference to
// BasePlusCommissionEmployee reference
BasePlusCommissionEmployee employee =
( BasePlusCommissionEmployee ) currentEmployee;

employee.BaseSalary *= 1.10M;
Console.WriteLine(
"new base salary with 10% increase is: {0:C}",
employee.BaseSalary );
} // end if

Console.WriteLine(
"earned {0:C}\n", currentEmployee.Earnings() );
} // end foreach



Re: Visual C# Language Using the IS operator in a FOREACH loop

Paul Louth

The type comes from the object itself, not from what's holding a referrence to the object.  So even though currentEmployee is a Employee referrence, it's referring to an object of a specific type.  So when you say:

if( currentEmployee is BasePlusCommissionEmployee )

You are comparing against the object that currentEmployee refers to, not against the declaration of currentEmployee itself.

However you should consider using inheritance over doing direct checks against type.





Re: Visual C# Language Using the IS operator in a FOREACH loop

James Curran

However you should consider using inheritance over doing direct checks against type.

ahem... "However you should consider using polymorphism over doing direct checks against type." (he is using inheritance)






Re: Visual C# Language Using the IS operator in a FOREACH loop

Jet Jaguar

 Paul Louth wrote:

You are comparing against the object that currentEmployee refers to, not against the declaration of currentEmployee itself.

Thank you for your responses.  Ok.  So let me see if I understand this...

A FOREACH variable used in an expression evaluates to the value of the variable.  The IS operator is comparing the "type" of the value of the variable rather than the "type" of the variable itself.

if( currentEmployee is BasePlusCommissionEmployee ) evaluates to true because currentEmployee refers to an element of an array that refers to a BasePlusCommissionEmployee object.

That being the case, if C# knows that the type of the object refered to by currentEmployee is a BasePlusCommissionEmployee type, why does the currentEmployee variable then have to be cast to a BasePlusCommissionEmployee type to get access to the properties of the refered object

In other words, since:

the value of currentEmployee is a BasePlusCommissionEmployee object

why can't you just:

currentEmployee.BaseSalary *= 1.10M;

 





Re: Visual C# Language Using the IS operator in a FOREACH loop

James Curran

That being the case, if C# knows that the type of the object refered to by currentEmployee is a BasePlusCommissionEmployee type, why does the currentEmployee variable then have to be cast to a BasePlusCommissionEmployee type to get access to the properties of the refered object

It knows at run-time that it's a BasePlusCommissionEmployee. At compile-time, it only knows that it can be any type derived from Employee.






Re: Visual C# Language Using the IS operator in a FOREACH loop

James Curran

ahem... "However you should consider using polymorphism over doing direct checks against type."

Paul Louth wrote:
jesus, call the pedant police!

What do you think the "ahem" at the start was --- It's the International Signal to call the Pedant Police.






Re: Visual C# Language Using the IS operator in a FOREACH loop

boban.s

You should use 'as' keyword for this situation, and avoid double casting.





Re: Visual C# Language Using the IS operator in a FOREACH loop

Axe22

  if( typeof( currentEmployee) == typeof( basePlusCommissionEmployee))

I'd probably try that, but I'm a C++ guy and very new to C# so what do I know. . .

 Actually, if it was me, I'd put an abstract function/enum combo in the base class that would allow for the test in a polymorphic manner:

partial class Employee
{
  public enum payType
  { 
    unknownType = 0,
    salariedType = 1,
    hourlyType = 2,
    commissionType = 3,
    basepluscommType = 4
  }

  public abstract payType PayType();
}

partial class SalariedEmployee : Employee
{
  public override payType PayType()
  {  return payType.salariedType; }
}

partial class BasePlusCommissionEmployee : CommissionEmployee
{
  public override payType PayType()
  {  return payType.basepluscommType; }
}

etc. & likewise for the other derived classes. Then...

if( currentEmployee.PayType() == payType.basepluscommType)
{ // do your stuff
}