C# 'as' Keyword and Derived Classes
I am working my way through "Sams Teach Yourself C# in 21 Days", obviously, this makes me a novice programmer. Please don't be too harsh. So far, being objective, I've feel I've done quite well understanding the topics. I am not looking for the answer, but hopefully be pointed in the right direction. :)
Anyway, I have this code:
// EXERCISE 11.4
using System;
public class Person
{
public string Name;
public Person()
{
}
public Person( string nm )
{
Name = nm;
}
public virtual void displayFullName()
{
Console.WriteLine( "Person {0}", Name );
}
}
class Employee : Person
{
//public ushort hireYear;
public Employee()
: base()
{
}
public Employee( string nm )
: base( nm )
{
}
public override void displayFullName()
{
Console.WriteLine( "Employee: {0}", Name );
}
}
class Contractor : Person
{
//public string Company;
public Contractor()
: base()
{
}
public Contractor( string nm )
: base( nm )
{
}
public override void displayFullName()
{
Console.WriteLine( "Contractor: {0}", Name );
}
public void DisplayCompany()
{
Console.WriteLine( "Company: {0}", Company );
}
}
class MyApplication
{
public static void Main()
{
Person [ ] myCompany = new Person[5];
int Counter = 0;
string Buffer, Buffer2;
do
{
do
{
Console.Write( "\nEnter \'c\' for Contractor, \'e\' for Employee then press ENTER: " );
Buffer = Console.ReadLine();
} while( Buffer == "" );
if( Buffer[0] == 'c' || Buffer[0] == 'C' )
{
Console.Write( "\nEnter the contractor\'s name: " );
Buffer = Console.ReadLine();
// DO OTHER CONTRACTOR STUFF
Contractor Contr = new Contractor( Buffer );
myCompany[Counter] = Contr as Person;
}
else if( Buffer[0] == 'e' || Buffer[0] == 'E' )
{
Console.Write( "\nEnter the employee\'s name: " );
Buffer = Console.ReadLine();
// DO OTHER EMPLOYEE STUFF
Employee emp = new Employee( Buffer );
myCompany[Counter] = emp as Person;
}
else
{
Person pers = new Person( "Not an Employee or Contractor" );
myCompany[Counter] = pers;
}
Counter++;
} while( Counter < 5 );
Console.WriteLine( "\n\n\n===========================" );
for( Counter = 0; Counter < 5; Counter++ )
{
if( myCompany[Counter] is Employee )
{
Console.WriteLine( "Employee: {0}", myCompany[Counter].Name );
}
else if( myCompany[Counter] is Contractor )
{
Console.WriteLine( "Contractor: {0}.", myCompany[Counter].Name );
}
else
{
Console.WriteLine( "Person: {0}", myCompany[Counter].Name );
}
}
Console.WriteLine( "===========================" );
Console.Read();
}
}
In the excercise I've to modify the Contractor or Employee class and add either a hireYear or Company data member respectively.
Which would look like this:
class Employee : Person
{
public ushort hireYear;
public Employee()
: base()
{
}
public Employee( string nm )
: base( nm )
{
}
public Employee( string nm, ushort hy )
: base( nm )
{
hireYear = hy;
}
public override void displayFullName()
{
Console.WriteLine( "Employee: {0}", Name );
}
}
OR
class Contractor : Person
{
public string Company;
public Contractor()
: base()
{
}
public Contractor( string nm )
: base( nm )
{
}
public Contractor( string nm, string c )
: base( nm )
{
Company = c;
}
public override void displayFullName()
{
Console.WriteLine( "Contractor: {0}", Name );
}
public void DisplayCompany()
{
Console.WriteLine( "Company: {0}", Company );
}
}
The changes to the MainApplication would be:
if( Buffer[0] == 'c' || Buffer[0] == 'C' )
{
string Buffer2;
Console.Write( "\nEnter the contractor\'s name: " );
Buffer = Console.ReadLine();
Console.Write( "\nEnter the contractor\'s company: " );
Buffer2 = Console.ReadLine();
Contractor Contr = new Contractor( Buffer, Buffer2 );
myCompany[Counter] = Contr as Person;
}
OR
else if( Buffer[0] == 'e' || Buffer[0] == '开发者_StackOverflowE' )
{
string BufferHireYear;
Console.Write( "\nEnter the employee\'s name: " );
Buffer = Console.ReadLine();
Console.Write( "\nEnter the year employee was hired: " );
BufferHireYear = Console.ReadLine();
Employee emp = new Employee( Buffer, BufferHireYear );
myCompany[Counter] = emp as Person;
}
I am quite happy until this point, I think. My confusion starts when I need to print out the results. My thinking is that when the objects are "cast" back into the myCompany array, they are added as objects of type person. The class for Person does not contain the data members Company or HireYear, so how can I access those data members?
Thank-you for reading through this posting, I am sure someone will be able to help.
I've got to learn.
Matt
You need to cast your objects back to Employee
so that you can use the members defined by Employee
.
Employee emp = (Employee)myCompany[Counter];
If myCompany[Counter]
isn't actually an Employee
, this will throw an InvalidCastException
.
When putting Employee
s in the array, you don't need to cast, since Employee
is always convertible to Person
.
You only need to cast explicitly if there is a chance that it won't work.
If you need printing/handling that is special for each sub-type you can special case the handling of each sub type in the output code.
foreach (Person person in myCompany)
{
if (person is Employee)
{
Employee e = (Employee)person;
Console.WriteLine("HireYear: {0}", e.HireYear);
// etc..
Another option would be for the Person base class to offer an abstract description property and each sub-class could override and then the output functions could call description when printing.
I may be jumping ahead here, but you may be interested at this point in the topic of "polymorphism". Taking advantage of polymorphism here, instead of having the calling code retrieve and print the individual details based on the type of Person, you simply tell the person to print or retrieve their own details based on what kind of person they are. So in this case, if you make a virtual function (similar to displayFullName) that prints out the full details of this instance, you can just call that on the person, and it will execute the appropriate version based on the actual type of Person on which it was invoked.
However, you can also cast the instance to the specific type and access it's members as described in the other answers.
精彩评论