Wednesday, August 29, 2007

Generics in C#

With .NET 2.0 , C# now has generic methods, generic classes, generic structures and generic interfaces. But in addition, it also has generic delegates

The question might arise as to why it was desirable to introduce generics in C#. One reason is that creating data structures like Stacks, Queues, ArrayLists, Hashtables and SortLIsts requires boxing and unboxing of data because these constructs are defined in terms of the object data type. Therefore when other data types are used in these data structure, it is necessary to use type conversion, i.e. boxing and unboxing. One of the problems with this process is that if these actions are preformed a large number of times, then they can use a large amount of clock time doing these processes. Further if the boxing and unboxing is performed incorrectly, then errors can occur. However the errors are usually runtime errors rather than compile time errors making it therefore more difficult to find and to correct. Generics in C# reduce the need for boxing and unboxing. As a result, the clock time requirements are reduced. In addition, if there are any errors in using the data, they may be more easily found at compile time rather than at run time making the program much more type safe.



Builtin Generic Interfaces and Generic Classes


The namespace: System.Collections.Generic contains several useful interfaces. Because of the frequency of the expected use of generics in C# programs, the following using appears by default above program created by the IDE:



using System.Collections.Generic;




The following table lists some of the generic interfaces that are included in this namespace:


ICollection

IComparable

IComparer

IDictionary

IEnumerable

IEnumerator

IList




Note: T is frequently used for the unknown data type, K is used for the unknown key type and V is used for the unknown value type. If more than one unknown is required, then the letters: R and S are used.

Several of the generic interfaces listed above have non-generic interface counter parts that were discussed earlier in the lectures.

In addition to the generic interfaces listed above, C# has several generic classes built in as well. These classes are also included in the namespace: System.Collections.Generic. The following table lists some of these builtin generic classes as well as their non-generic counterparts:


Open table as spreadsheet Generic Class
NonGeneric Conterpart in System.Collection

Collection
CollectionBase

Comparer
Comparer

Dictionary
HashTable

List
ArrayList

LinkedList

Queue
Queue

SortedDictionary
SortedList

Stack
Stack




For example the generic class List above could be used to manage a list of any data type. Some of the methods for this class are:


Open table as spreadsheet Method
Purpose

Add()
Adds elements to the list

BinarySearch()
Locates a particular element in the list returning a position

Contains()
Determine if an element is in the list returning a bool

Remove()
Removes an element and returns a bool to indicate whether it was removed.

this[int index]
An indexer with {get; set;}




Suppose that you wanted to create a list of objects for the class: People. Using List, this could be done by the following definition:



List theCustomers = new List();




This List could therefore be managed as in the console program: CustomersList.cs. Notice how this program works similar to using an ArrayList.





Generic Methods




Generic Classes




Generic Class Inheritance from Classes and Interfaces

Explicit Interface Implementation

Suppose that theClass is derived from two different and unrelated interfaces: Interface1 and Interface2. Further suppose that each of these interfaces has a method: theMethod() with the same signature. The question is how to define theClass so that each theMethod() is implemented. To do this requires what is called an explicit implementation. An explicit implementation requires that at least one of the implemented methods of theClass has its name preceded with the name of the interface (which in this case is called an explicit implementation of the method). When this is done, the implemented method does not have an access specifier. An explicit implementation helps to distinguish which implementation is being used if there is more than one.

For example the two methods could be defined in the class as in the following:



theMethod()
{
....
}
Interface2.theMethod()
{
....
}




That is suppose the program contained the following code:



interface Interface1
{
void theFirstOne();
void theMethod();
}
interface Interface2
{
void theSecondOne();
void theMethod();
}
class theClass: Interface1, Interface2
{
. ........
public void theFirstOne()
{
.....
}
public void theSecondOne()
{
......
}

// The following will implement the Interface1 method
//
public void theMethod()
{
...
}
// The following will be an explicit implementation of
// the Interface2 method. Notice no access specifier.
//
Interface2.theMethod()
{
....
}
}




so that when defining an instance of theClass, as in the following:



theClass theObject = new theClass();




and then the call of theMethod() would be the following:



theObject.theMethod();




but this would be calling theMethod() that was derived from the interface: Interface1 without any additional explicit notation.

In order to access the explicit implementation: Interface2.theMethod() a reference to the interface: Interface2 must be declared as in the following:



Interface2 theReference = (Interface2) theObject;




Then, using theReference, the explicit implementation may be accessed as in the following:



theReference.theMethod();




For an example of this concept see: explicitImplimentation.cs

The example above only made one of theMethod() functions an explicit implementation. What may be desirable would be to make each an explicit implementation. Some authors on C# recommend that each method inherited from an interface be an explicit implementation. In this way there would be fewer problems when the code was modified by other programmers or if the code was in the component library with little or no documentation to warn about the problems that may be encountered deriving a class from the component interfaces.

Interface : Using the is and the as Operators

Some times it is not clear whether a reference to an interface does in fact have access to the class' object. This condition may be checked by using the is or the as operator. For example suppose that a program has a class: theClass and it is derived from the interface: Interface. Then the question is whether theReference of Interface can be used to access an object of theClass in the following:



theClass theClassReference = new theClass();
Interface theReference = (Interface) theClassReference;




Further suppose that theClass has a method: theMethod(). What is desired is whether:



theReference.theMethod();




is syntactically correct. If it is not, then an exception of type: System.InvalidCastException is thrown. (More will be said about exceptions in a later lecture.)

To prevent this exception from occurring, this relationship could be tested prior to implementing the type casting and the call of the method: theMethod() by theReference using the following code:



if((theClassReference is Interface)
{
Interface theReference = (Interface) theClassReference;
theReference.theMethod();
}




As a result of the above, theReference would only call theMethod() should theClass have implemented the interface: Interface.

The operator as works similar to is. Using as, the above could be implemented in the following manner:



theClassReference = new theClass();
Interface theReference = theClassReference as Interface;
if(theReference != null)
theReference.theMethod();




In this if( ) statement theReference would be null should it not represent the object of theClass to which theClassReference refers.
// program_id overrideInterface.cs
// description This program demonstrates a class
// derived from a class that overrides
// the base class' implementation
// of the interface's method.
//

using System;

namespace theChecking
{
interface IAccounts
{
decimal theBalance {set; get;}
void Deposit(decimal theAmount);

void Withdrawal(decimal theAmount);
}

interface IFee: IAccounts
{
decimal theFee {get; set;}
void CalculateFee();
}

class Checking: IFee
{
private decimal Fee;
public decimal theFee
{
get
{
return Fee;
}
set
{

Fee = value;
}
}

private decimal Balance;
public decimal theBalance
{
get
{
return Balance;
}
set
{
Balance = value;
}
}
public Checking()
{
Balance = 0.00M;
}
public void Deposit(decimal theAmount)
{
Balance += theAmount;
}
public void Withdrawal(decimal theAmount)
{
Balance -= theAmount;
}
public virtual void CalculateFee()
{
Balance -= Fee;
}
}
class Savings : Checking
{
public override void CalculateFee()
{
theBalance *= (1 + theFee);
}
public decimal ShowInterest()
{
return (theBalance * theFee);
}

}
class theProgram
{
static void Main()
{

Checking checkingAccount = new Checking();

Savings savingsAccount = new Savings();

Console.Clear();

Console.Write("What is the checking account fee? ");
checkingAccount.theFee = Decimal.Parse(Console.ReadLine());

Console.Write("\nWhat was the checking account deposits? ");
checkingAccount.Deposit(Decimal.Parse(Console.ReadLine()));

Console.Write("What was the checking account withdrawals? ");
checkingAccount.Withdrawal(Decimal.Parse(Console.ReadLine()));


if(checkingAccount.theBalance <= 500.00m)
{
checkingAccount.CalculateFee();
Console.WriteLine("\nThe checking account was charged a fee of {0:c}",
checkingAccount.theFee);
}

Console.WriteLine("\nCurrent balance of the checking account is {0:c}.",
checkingAccount.theBalance);

Console.Write("\n\nWhat is the savings account interest rate? ");
savingsAccount.theFee = Decimal.Parse(Console.ReadLine())/100;

Console.Write("\nWhat was the savings account deposits? ");
savingsAccount.Deposit(Decimal.Parse(Console.ReadLine()));

Console.Write("What was the savings account withdrawals? ");
savingsAccount.Withdrawal(Decimal.Parse(Console.ReadLine()));

if(savingsAccount.theBalance >= 500.00m)

{
Console.WriteLine("\nThe savings account was awarded an interest fee of {0:c}",
savingsAccount.ShowInterest());
savingsAccount.CalculateFee();
}
Console.WriteLine("\nCurrent balance of the savings account is {0:c}.",
savingsAccount.theBalance);

Console.WriteLine("\n\n");
Console.ReadKey();
}

}
}

Virtual Methods in C#

Earlier in the notes, an example: inheritance5.cs was shown where both the base class and the derived class both have methods with the same name and signature. As was seen, this was permitted by the compiler but a warning error was issued. To overcome this warning error, the modifier new was used in the example: inheritance3.cs on the derived class' method to inform the compiler that the definition of the derived class' method was hiding the base class' method. This example also compiled and ran but there were no warning errors.

Sometimes it is desirable to force the derived class to either use the base class' method or to override the base class' method with an entirely different method but with the same name. In either case the base class' method must have the modifier: virtual. When this modifier is used, then the modifier new may not be used. Instead the modifier override must be used if the derived class is to have a method with the same name as the base class. To see an example where the base class is using the modifier virtual but the derived class does not use these names see: inheritance7.cs. To see an example where the base class uses the modifier virtual and the derived class defines methods with the same name by using the modifier: override see: inheritance6.cs. Recall how when the ToString() method was discussed in a previous section, that the modifier override was used. The reason for this is that the method ToString() is a virtual method of the class: System.Object.


// program_id inheritance1.cs
// written?_by don voils
// date_written 12/11/2006
// description This program demonstrates how
// to use inheritance.
//

using System;

class theProgram
{
public class Customer
{
private string CustomerID;
private string CustomerName;
private string CustomerAddress;
private string CustomerCity;
private string CustomerState;
private string CustomerZipCode;

public void setCustomerID(string ID)
{
CustomerID = ID;
}
public void setCustomerName(string Name)
{
CustomerName = Name;
}
public void setCustomerAddress(string Address)
{
CustomerAddress = Address;
}
public void setCustomerCity(string City)
{
CustomerCity = City;
}
public void setCustomerState(string State)
{

CustomerState = State;
}
public void setCustomerZipCode(string Code)
{
CustomerZipCode = Code;
}
public string getCustomerID()
{
return CustomerID;
}
public string getCustomerName()
{
return CustomerName;
}
public string getCustomerAddress()
{
return CustomerAddress;
}
public string getCustomerCity()
{
return CustomerCity;
}
public string getCustomerState()
{
return CustomerState;
}
public string getCustomerZipCode()
{
return CustomerZipCode;
}
}

public class Invoice : Customer
{
private decimal InvoiceAmount;

public void setInvoiceAmount(decimal Amount)
{
InvoiceAmount = Amount;
}
public decimal getInvoiceAmount()
{
return InvoiceAmount;

}
}
static void Main()
{
Invoice theTransaction = new Invoice();
Console.Write("What is the customer's ID? ");
theTransaction.setCustomerID(Console.ReadLine());

Console.Write("What is the customer's name? ");
theTransaction.setCustomerName(Console.ReadLine());

Console.Write("What is the customer's address? ");
theTransaction.setCustomerAddress(Console.ReadLine());

Console.Write("What is the customer's city? ");
theTransaction.setCustomerCity(Console.ReadLine());

Console.Write("What is the customer's state? ");
theTransaction.setCustomerState(Console.ReadLine());

Console.Write("What is the customer's zip code? ");
theTransaction.setCustomerZipCode(Console.ReadLine());

Console.Write("What is the amount of the invoice? ");
theTransaction.setInvoiceAmount(Decimal.Parse(Console.ReadLine()));

Console.Clear();

Console.WriteLine("Customer ID: {0}", theTransaction.getCustomerID());
Console.WriteLine("Customer Name: {0}", theTransaction.getCustomerName());
Console.WriteLine("Customer Address: {0}", theTransaction.getCustomerAddress());
Console.WriteLine("Customer City: {0}", theTransaction.getCustomerCity());
Console.WriteLine("Customer State: {0}", theTransaction.getCustomerState());
Console.WriteLine("Customer Zip Code: {0}", theTransaction.getCustomerZipCode());
Console.WriteLine("Invoice Amount: {0,15:c}\n\n", theTransaction.getInvoiceAmount());
Console.ReadKey();
}


}



// program_id inheritance2.cs
// written?_by don voils
// date_written 12/11/2006
// description This program demonstrates how
// to use inheritance.
//

using System;

class theProgram
{
public class People
{
private string PeopleID;
private string PeopleName;
private string PeopleAddress;
private string PeopleCity;
private string PeopleState;
private string PeopleZipCode;

public void setPeopleID(string ID)
{
PeopleID = ID;
}
public void setPeopleName(string Name)
{
PeopleName = Name;
}
public void setPeopleAddress(string Address)
{
PeopleAddress = Address;
}
public void setPeopleCity(string City)
{
PeopleCity = City;
}
public void setPeopleState(string State)
{

PeopleState = State;
}
public void setPeopleZipCode(string Code)
{
PeopleZipCode = Code;
}
public string getPeopleID()
{
return PeopleID;
}
public string getPeopleName()
{
return PeopleName;
}
public string getPeopleAddress()
{
return PeopleAddress;
}
public string getPeopleCity()
{
return PeopleCity;
}
public string getPeopleState()
{
return PeopleState;
}
public string getPeopleZipCode()
{
return PeopleZipCode;
}
}
public class Employee : People
{
private char PayType;
private decimal PayRate;
private decimal GrossPay;
public void setPayType(char Type)
{
PayType = Type;
}
public char getPayType()
{
return PayType;

}
public void setPayRate(decimal Rate)
{
PayRate = Rate;
}
public decimal getPayRate()
{
return PayRate;
}
public void setGrossPay(decimal Amount)
{
GrossPay = Amount;
}
public decimal getGrossPay()
{
return GrossPay;
}
}
public class Customer : People
{
private decimal BalancetDue;

public void setBalanceDue(decimal Amount)
{
BalancetDue = Amount;
}
public decimal getBalanceDue()
{
return BalancetDue;
}
}
public class Vendor : People
{
private decimal AmountOwed;

public void setAmountOwed(decimal Amount)
{
AmountOwed = Amount;
}
public decimal getAmountOwed()
{
return AmountOwed;
}

}
static void Main()
{
bool processAgain = true;
while (processAgain == true)
{
Console.WriteLine(" Account Type\n");
Console.WriteLine(" 1. Employee");
Console.WriteLine(" 2. Customer");
Console.WriteLine(" 3. Vendor");
Console.Write("\n Which? ");
char TransactionType = Char.Parse(Console.ReadLine());
Console.Clear();
switch (TransactionType)
{
case '1':
processEmployee();
break;
case '2':
processCustomer();
break;
case '3':
processVendor();
break;
default:
Console.WriteLine("You selected an incorrect type." +
"Please try again.\n");
break;
}
Console.Write("\nDo you want to process another? Y or N ");
TransactionType = Char.Parse(Console.ReadLine());
Console.Clear();
if ((TransactionType != 'y') && (TransactionType != 'Y'))
processAgain = false;
else
processAgain = true;
}
}

static void processEmployee()
{
Employee theTransaction = new Employee();
Console.Write("What is the employee's ID? ");

theTransaction.setPeopleID(Console.ReadLine());

Console.Write("What is the employee's name? ");
theTransaction.setPeopleName(Console.ReadLine());

Console.Write("What is the employee's address? ");
theTransaction.setPeopleAddress(Console.ReadLine());

Console.Write("What is the employee's city? ");
theTransaction.setPeopleCity(Console.ReadLine());

Console.Write("What is the employee's state? ");
theTransaction.setPeopleState(Console.ReadLine());

Console.Write("What is the employee's zip code? ");
theTransaction.setPeopleZipCode(Console.ReadLine());

char theType;
do
{
Console.Write("What is the employee's pay type (H:Hourly or S:Salaried? ");
theType = Char.Parse(Console.ReadLine());
} while ((theType != 'H') && (theType != 'h') && (theType != 'S') && (theType != 's'));
theTransaction.setPayType(theType);

Console.Write("What is the employee's pay rate? ");
theTransaction.setPayRate(Decimal.Parse(Console.ReadLine()));

Console.Write("What is the employee's gross pay? ");
theTransaction.setGrossPay(Decimal.Parse(Console.ReadLine()));
Console.WriteLine("\n\n");

Console.Clear();
Console.WriteLine("Employee ID: {0}", theTransaction.getPeopleID());
Console.WriteLine("Employee Name: {0}", theTransaction.getPeopleName());
Console.WriteLine("Employee Address: {0}", theTransaction.getPeopleAddress());
Console.WriteLine("Employee City: {0}", theTransaction.getPeopleCity());
Console.WriteLine("Employee State: {0}", theTransaction.getPeopleState());
Console.WriteLine("Employee Zip Code: {0}", theTransaction.getPeopleZipCode());
Console.WriteLine("Employee Pay Type: {0}", theTransaction.getPayType());
Console.WriteLine("Employee Pay Rate: {0,15:c}", theTransaction.getPayRate());
Console.WriteLine("Employee Gross Pay: {0,15:c}", theTransaction.getGrossPay());
Console.WriteLine("\n\n");

}

static void processCustomer()
{
Customer theTransaction = new Customer();
Console.Write("What is the customer's ID? ");
theTransaction.setPeopleID(Console.ReadLine());

Console.Write("What is the customer's name? ");
theTransaction.setPeopleName(Console.ReadLine());

Console.Write("What is the customer's address? ");
theTransaction.setPeopleAddress(Console.ReadLine());

Console.Write("What is the customer's city? ");
theTransaction.setPeopleCity(Console.ReadLine());

Console.Write("What is the customer's state? ");
theTransaction.setPeopleState(Console.ReadLine());

Console.Write("What is the customer's zip code? ");
theTransaction.setPeopleZipCode(Console.ReadLine());

Console.Write("What is the cutomer's balance due? ");
theTransaction.setBalanceDue(Decimal.Parse(Console.ReadLine()));
Console.WriteLine("\n\n");

Console.Clear();
Console.WriteLine("Customer ID: {0}", theTransaction.getPeopleID());
Console.WriteLine("Customer Name: {0}", theTransaction.getPeopleName());
Console.WriteLine("Customer Address: {0}", theTransaction.getPeopleAddress());
Console.WriteLine("Customer City: {0}", theTransaction.getPeopleCity());
Console.WriteLine("Customer State: {0}", theTransaction.getPeopleState());
Console.WriteLine("Customer Zip Code: {0}", theTransaction.getPeopleZipCode());
Console.WriteLine("Cusomter Balance Due: {0,15:c}", theTransaction.getBalanceDue());
Console.WriteLine("\n\n");
}


static void processVendor()
{
Vendor theTransaction = new Vendor();
Console.Write("What is the vendor's ID? ");

theTransaction.setPeopleID(Console.ReadLine());

Console.Write("What is the vendor's name? ");
theTransaction.setPeopleName(Console.ReadLine());

Console.Write("What is the vendor's address? ");
theTransaction.setPeopleAddress(Console.ReadLine());

Console.Write("What is the vendor's city? ");
theTransaction.setPeopleCity(Console.ReadLine());

Console.Write("What is the vendor's state? ");
theTransaction.setPeopleState(Console.ReadLine());

Console.Write("What is the vendor's zip code? ");
theTransaction.setPeopleZipCode(Console.ReadLine());

Console.Write("What is the amount owed the vendor? ");
theTransaction.setAmountOwed(Decimal.Parse(Console.ReadLine()));
Console.WriteLine("\n\n");

Console.Clear();
Console.WriteLine("Vendor ID: {0}", theTransaction.getPeopleID());
Console.WriteLine("Vendor Name: {0}", theTransaction.getPeopleName());
Console.WriteLine("Vendor Address: {0}", theTransaction.getPeopleAddress());
Console.WriteLine("Vendor City: {0}", theTransaction.getPeopleCity());
Console.WriteLine("Vendor State: {0}", theTransaction.getPeopleState());
Console.WriteLine("Vendor Zip Code: {0}", theTransaction.getPeopleZipCode());
Console.WriteLine("Amount Owed: {0,15:c}", theTransaction.getAmountOwed());
Console.WriteLine("\n\n");
}
}



// program_id inheritance3.cs
// written_by don voils
// date_written 10/2/2006
// description In this example the base class has a
// protected attribute that is accessible
// in the derived class. In addition the
// derived class has methods with the
// same name as the base class and overcomes
// this restriction by using the keyword word: new.
//

using System;

namespace constructor
{
class stuff
{
protected int member;

public void setMember(int a)
{
member = a;
Console.WriteLine("Through the stuff class using the setMember() method.\n");
}

public void print()
{
Console.WriteLine("Through the stuff class using the print() method: member = {0}.\n", member);
}
}

class stuff1 : stuff
{
public new void setMember(int a)
{
member = a;
Console.WriteLine("Through the class stuff1 using the setMember() method.\n");
}

public new void print()
{
Console.WriteLine("Through the class stuff1 using the print() method: member = {0}.\n", member);
}
}

class myProgram
{
static void Main()
{
Console.WriteLine("Defining theObject an object of the class stuff.\n");

stuff theObject = new stuff();

theObject.setMember(10);

theObject.print();

Console.WriteLine("\n\n");

Console.WriteLine("Defining object1 an object of the class stuff1.\n");

stuff1 object1 = new stuff1();

object1.setMember(15);

object1.print();

Console.WriteLine("\n\n");
Console.ReadKey();
}
}
}



// program_id inheritance4.cs
// written?_by don voils
// date_written 12/11/2006
// description This program demonstrates how
// to prevent inheritance. The program is
// the same as inheritance1.cs except
// the class Customer is sealed. The
// program inheritance1.cs compiled and
// ran but this program will not.
//

using System;

class theProgram
{
sealed public class Customer
{
private string CustomerID;
private string CustomerName;
private string CustomerAddress;
private string CustomerCity;
private string CustomerState;
private string CustomerZipCode;

public void setCustomerID(string ID)
{
CustomerID = ID;
}
public void setCustomerName(string Name)
{
CustomerName = Name;
}
public void setCustomerAddress(string Address)
{
CustomerAddress = Address;
}
public void setCustomerCity(string City)
{

CustomerCity = City;
}
public void setCustomerState(string State)
{
CustomerState = State;
}
public void setCustomerZipCode(string Code)
{
CustomerZipCode = Code;
}
public string getCustomerID()
{
return CustomerID;
}
public string getCustomerName()
{
return CustomerName;
}
public string getCustomerAddress()
{
return CustomerAddress;
}
public string getCustomerCity()
{
return CustomerCity;
}
public string getCustomerState()
{
return CustomerState;
}
public string getCustomerZipCode()
{
return CustomerZipCode;
}
}

public class Invoice : Customer
{
private decimal InvoiceAmount;

public void setInvoiceAmount(decimal Amount)
{
InvoiceAmount = Amount;

}
public decimal getInvoiceAmount()
{
return InvoiceAmount;
}
}
static void Main()
{
Invoice theTransaction = new Invoice();
Console.Write("What is the customer's ID? ");
theTransaction.setCustomerID(Console.ReadLine());

Console.Write("What is the customer's name? ");
theTransaction.setCustomerName(Console.ReadLine());

Console.Write("What is the customer's address? ");
theTransaction.setCustomerAddress(Console.ReadLine());

Console.Write("What is the customer's city? ");
theTransaction.setCustomerCity(Console.ReadLine());

Console.Write("What is the customer's state? ");
theTransaction.setCustomerState(Console.ReadLine());

Console.Write("What is the customer's zip code? ");
theTransaction.setCustomerZipCode(Console.ReadLine());

Console.Write("What is the amount of the invoice? ");
theTransaction.setInvoiceAmount(Decimal.Parse(Console.ReadLine()));

Console.Clear();

Console.WriteLine("Customer ID: {0}", theTransaction.getCustomerID());
Console.WriteLine("Customer Name: {0}", theTransaction.getCustomerName());
Console.WriteLine("Customer Address: {0}", theTransaction.getCustomerAddress());
Console.WriteLine("Customer City: {0}", theTransaction.getCustomerCity());
Console.WriteLine("Customer State: {0}", theTransaction.getCustomerState());
Console.WriteLine("Customer Zip Code: {0}", theTransaction.getCustomerZipCode());
Console.WriteLine("Invoice Amount: {0,15:c}", theTransaction.getInvoiceAmount());
Console.WriteLine("\n\n");
}

}



// program_id inheritance5.cs
// written_by don voils
// date_written 10/2/2006
// description This example is contains two class
// one of which is derived from the other.
// The base class and the derived class contain
// methods with the same name. While the program
// compiles and runs, it contains several warning
// error notifying the programmer that the two
// classes have methods with the same names.
//

using System;

namespace constructor
{
class stuff
{
protected int member;

public void setMember(int a)
{
member = a;
Console.WriteLine("Through the stuff class using the setMember() method.\n");
}

public void print()
{
Console.WriteLine("Through the stuff class using the print() method: member = {0}.\n"
, member);
}
}

class stuff1 : stuff
{
// has the same name as a method in the base class.
//
public void setMember(int a)

{
member = a;
Console.WriteLine("Through the class stuff1 using the setMember() method.\n");
}

// has the same name as a method in the base class.
public void print()
{
Console.WriteLine("Through the class stuff1 using the print() method: member = {0}.\n",
member);
}
}

class myProgram
{
static void Main()
{
Console.WriteLine("Defining theObject an object of the class stuff.\n");

stuff theObject = new stuff();

theObject.setMember(10);

theObject.print();

Console.WriteLine("\n\n");

Console.WriteLine("Defining object1 an object of the class stuff1.\n");

stuff1 object1 = new stuff1();

object1.setMember(15);

object1.print();

Console.WriteLine("\n\n");
Console.ReadKey();
}
}
}



// program_id inheritance6.cs
// written_by don voils
// date_written 10/2/2006
// description In this example the base class has a
// protected attribute that is accessible
// in the derived class.
//
// In addition the derived class has methods with the
// same name as the base class. This overcomes
// this restriction by using the keyword words: virtual
// in the base class and overridden in the derived class.
//

using System;

namespace theProgram
{
class theBase
{
protected int member;

virtual public void setMember(int a)
{
member = a;
Console.WriteLine("Through the theBase class using the setMember() method.\n");
}

virtual public void print()
{
Console.WriteLine("Through the theBase class using the print() method: member = {0}.\n", member);
}
}

// Notice that the attribute member of theBase class was
// declared as protected, therefore it is accessible in the
// derived class as though it was a private attribute
// of the derived class.
//
class theDerived : theBase
{

override public void setMember(int a)
{
member = a;
Console.WriteLine("Through the class theDerived using setMember() method.\n");
}

override public void print()
{
Console.WriteLine("Through the class theDerived using print() method: member = {0}.\n", member);
}
}

class myProgram
{
static void Main()
{
Console.WriteLine("Defining theBaseObject an object of the class theBase.\n");

theBase theBaseObject = new theBase();

theBaseObject.setMember(10);

theBaseObject.print();

Console.WriteLine("\n\n");

Console.WriteLine("Defining theDerivedObject an object of the class theDerived.\n");

theDerived theDerivedObject = new theDerived();

theDerivedObject.setMember(15);

theDerivedObject.print();

Console.WriteLine("\n\n");
Console.ReadKey();
}
}
}



// program_id inheritance7.cs
// written_by don voils
// date_written 10/2/2006
// description In this example the base class has a
// methods that are declared as virtual.
// The derived class does not have methods
// by these names. However the program
// compiles and runs.
//

using System;

namespace theProgram
{
class theBase
{
protected int member;

virtual public void setMember(int a)
{
member = a;
Console.WriteLine("Through the theBase class using the setMember() method.\n");
}

virtual public void print()
{
Console.WriteLine("Through the theBase class using the print() method: member = {0}.\n", member);
}
}

class theDerived : theBase
{

}

class myProgram
{
static void Main()
{
Console.WriteLine("Defining theBaseObject an object of the class theBase.\n");

theBase theBaseObject = new theBase();

theBaseObject.setMember(10);

theBaseObject.print();

Console.WriteLine("\n\n");

Console.WriteLine("Defining theDerivedObject an object of the class theDerived.\n");

theDerived theDerivedObject = new theDerived();

theDerivedObject.setMember(15);

theDerivedObject.print();

Console.WriteLine("\n\n");
Console.ReadKey();
}
}
}

Base n Derived Class references : C#

References to a Base Class Manipulate Objects of the Derived Class
Polymorphism in C# is slightly different from that in C++. As you may recall, in C++ part of the polymorphism feature used pointers and part of it used references. Since C# does not use pointers but does use references, only the reference part is used.

For example, references to a base class may be used to reference a derived class' object. In this way, an object of a derived class may be treated as an object of the base class.

For example suppose a program has two classes: theBase and theDerived where theDerived is derived from theBase. Suppose the following definition of a reference of the derived class:



theDerived theDerivedReference = new theDerived();




With the following definition, the reference: theBaseReference references the derived object referenced by theDerivedReference.



theBase theBaseReference = theDerivedReference;




This last statement would then permit theBaseReference to manipulate the theBase class' contents of the object to which theDerivedRefence refers to.

For excample see theReference1.cs. One of the problems with this relationship is similar to the problem with pointers in C++. That is the reference: theBaseReference may only refer to the base class members of the derived class object. It can not refer to the derived class members of the object. Notice in this program where theBaseReference is trying to access the method: show_theDerived() if the comment symbols are removed, the program will not compile.

The reverse relationship is not possible. Meaning, that a reference to a derived class may not be used with an object of the base class. If a program does, then there will be a compiler error. For example if the following code replaced the code in the previous example the program would not compile:t



theBase theBaseReference = new theBase(2);
theDerived theDerivedReference;

theDerivedReference = theBaseReference;




See theReference3.cs.

In addition if anotherDerived is a class that is itself derived from theDerived class, then theBaseReference may also be used to access theBase class' part of an object of anotherDerived class' object. For example see theReference2.cs.


// program_id theReference1.cs
// written by don voils
// date_written 10/3/2006
// Descriptioin The program shows how references to a base
// class can be used to access the base class
// part of an object of the derived class.
//

using System;

class theProgram
{
public class theBase
{
private short theBaseMember;
public theBase(short theShort)
{
theBaseMember = theShort;
}
public short show_theBase()
{
return theBaseMember;
}
}

public class theDerived : theBase
{
private short theDerivedMember;
public theDerived(short firstShort, short secondShort)
: base(firstShort)
{
theDerivedMember = secondShort;
}
public short show_theDerived()
{
return theDerivedMember;
}
}

static void Main()
{

theBase theBaseReference;
theDerived theDerivedReference = new theDerived(1, 2);

theBaseReference = theDerivedReference;

Console.WriteLine("The value of theBaseMember is {0}.\n",
theBaseReference.show_theBase());

//
// The following line will not compile. Why?
//
// Console.WriteLine("The value of theDerivedMember is {0}.\n",
// theBaseReference.show_theDerived());

Console.WriteLine("\n\n");
Console.ReadKey();
}


}



// program_id theReference2.cs
// written by don voils
// date_written 10/3/2006
// Descriptioin The program shows how references to a base
// class can be used to access the base class
// part of an object of a class that is derived from a
// class that is derived from the base.
//

using System;

class theProgram
{
public class theBase
{
private short theBaseMember;
public theBase(short theShort)
{
theBaseMember = theShort;
}
public short show_theBase()
{
return theBaseMember;
}
}

public class theDerived : theBase
{
private short theDerivedMember;
public theDerived(short firstShort, short secondShort)
: base(firstShort)
{
theDerivedMember = secondShort;
}
public short show_theDerived()
{
return theDerivedMember;
}

}

public class anotherDerived : theDerived
{
private short anotherDerivedMember;
public anotherDerived(short firstShort, short secondShort, short thirdShort)
: base(firstShort, secondShort)
{
anotherDerivedMember = thirdShort;
}
public short show_anotherDerived()
{
return anotherDerivedMember;
}
}

static void Main()
{
theBase theBaseReference;
theDerived theDerivedReference = new theDerived(1, 2);

theBaseReference = theDerivedReference;

Console.WriteLine("The value of theBaseMember is {0}.\n",
theBaseReference.show_theBase());

anotherDerived anotherDerivedReference = new anotherDerived(5, 6, 7);

theBaseReference = anotherDerivedReference;

Console.WriteLine("The value of theBaseMember is {0}.\n\n",
theBaseReference.show_theBase());

Console.ReadKey();
}


}



// program_id theReference3.cs
// written by don voils
// date_written 10/3/2006
// Descriptioin The program shows that a reference to
// a derived class may not be used to reference
// a base class object.
//

using System;

class theProgram
{
public class theBase
{
private short theBaseMember;
public theBase(short theShort)
{
theBaseMember = theShort;
}
public short show_theBase()
{
return theBaseMember;
}
}

public class theDerived : theBase
{
private short theDerivedMember;
public theDerived(short firstShort, short secondShort)
: base(firstShort)
{
theDerivedMember = secondShort;
}
public short show_theDerived()
{
return theDerivedMember;
}
}

static void Main()
{
theBase theBaseReference = new theBase(2);
theDerived theDerivedReference;

theDerivedReference = theBaseReference;

Console.WriteLine("\n\n");
Console.ReadKey();
}


}

Abstract in C# 2005

Abstract Classes and Methods
Two additional features of the C# polymorphism are abstract methods and abstract classes.

To define an abstract method the keyword: abstract must be placed in front of the method's definition and the abstract method can have no body as in the following code:



abstract public void theMethod();




In the case of classes, the keyword: abstract must appear before the word class in the definition of the class as in the following code:



abstract public class theClass
{
....
}




An abstract class must contain one or more abstract methods. Any class that contains an abstract method must be defined as an abstract class. An abstract class may not have any defined objects. In addition to the abstract methods, an abstract class may also have non abstract methods as well.

Abstract classes and methods must be defined public.

Any derived class of an abstract class must override the inherited abstract methods in order to permit the derived objects to be defined. If the abstract methods are not overridden, then the derived class would be considered abstract and any attempts to define objects for such a derived class would fail. As discussed above, this is done by placing the word override in front of the method's definition. For example see theAbstract1.cs.

While a class derived from an abstract class must implement each abstract method of the abstract class by overriding it, this is not true if a class is in turn derived from this derived class. For example see theAbstract2.cs.

One of the purposes of abstract classes is to provide a base from which other classes may be derived that in turn override the abstract methods. A second purpose is to permit the references of the abstract class to access the overridden methods as if they were references of the derived classes. For example see theAbstract3.cs.



// program_id theAbstract1.cs
// written by don voils
// date_written 10/3/2006
// Descriptioin The program shows how an abstract
// class and method can be defined as
// well as how to derive a class from the
// abstract class. If the keyword: override
// is removed from the definition of the
// method show() in the derived class,
// the program will not compile.
//

using System;

class theProgram
{
abstract public class theBase
{
private short theBaseMember;
public theBase(short theShort)
{
theBaseMember = theShort;
}
abstract public short show();
}

public class theDerived : theBase
{
private short theDerivedMember;
public theDerived(short firstShort, short secondShort)
: base(firstShort)
{
theDerivedMember = secondShort;
}
override public short show()
{
return theDerivedMember;
}

}

static void Main()
{
theDerived theDerivedReference = new theDerived(1, 2);

Console.WriteLine("The value of theBaseMember is {0}.\n\n",
theDerivedReference.show());

Console.ReadKey();
}


}



// program_id theAbstract2.cs
// written by don voils
// date_written 10/3/2006
// Descriptioin This program shows how an abstract
// class and method can be defined as
// well as how to derive a class from a class
// that is derived from an abstract class.
// In this case, this second derived class
// does not have to override the base class'
// abstract method.
//

using System;

class theProgram
{
abstract public class theBase
{
private short theBaseMember;
public theBase(short theShort)
{
theBaseMember = theShort;
}
abstract public short show();
}

public class theDerived : theBase
{
private short theDerivedMember;
public theDerived(short firstShort, short secondShort): base(firstShort)
{
theDerivedMember = secondShort;
}
override public short show()
{
return theDerivedMember;
}
}

public class nextDerived : theDerived
{
private short theNextDerivedMember;

public nextDerived(short firstShort, short secondShort, short thirdShort)
: base(firstShort, secondShort)
{
theNextDerivedMember = thirdShort;
}
public short showNextDerived()
{
return theNextDerivedMember;
}
}

static void Main()
{
nextDerived theReference = new nextDerived(1, 2, 3);

Console.WriteLine("The value of theNextDerivedMember is {0}.\n\n",
theReference.show());

Console.ReadKey();
}


}



// program_id theAbstract3.cs
// written by don voils
// date_written 10/3/2006
// Descriptioin This program shows how an abstract
// class and method can be defined as
// well as how to derive a class from a class
// that is derived from an abstract class.
// In this case, a second derived class
// is derived from the first derived class.
// In this program a reference to the abstract
// base class is used to access methods of
// each of the derived classes as if it was
// a reference to the respecitive classes.
// Without this base class being abstract,
// this reference would have been forced to
// access the base class' method which would
// have been impossible because it is in turn
// abstract.
//

using System;

class theProgram
{
abstract public class theBase
{
private short theBaseMember;
public theBase(short theShort)
{
theBaseMember = theShort;
}
abstract public short show();
}

public class theDerived : theBase
{
private short theDerivedMember;
public theDerived(short firstShort, short secondShort) : base(firstShort)

{
theDerivedMember = secondShort;
}
override public short show()
{
return theDerivedMember;
}
}

public class nextDerived : theDerived
{
private short theNextDerivedMember;

public nextDerived(short firstShort, short secondShort, short thirdShort)
: base(firstShort, secondShort)
{
theNextDerivedMember = thirdShort;
}
override public short show()
{
return theNextDerivedMember;
}
}

static void Main()
{

theDerived theDerivedReference = new theDerived(4, 5);

theBase theBaseReference = theDerivedReference;

Console.WriteLine("The value of theDerivedMember is {0}.\n",
theBaseReference.show());

nextDerived theNextDerivedReference = new nextDerived(1, 2, 3);

theBaseReference = theNextDerivedReference;

Console.WriteLine("The value of theNextDerivedMember is {0}.\n\n",
theBaseReference.show());

Console.ReadKey();
}

}