public class Exercise
{
static int Main()
{
var exo = new Generator();
// Call the version of the method that displays an integer
exo.Show(246);
// Call the version of the method that displays a character
exo.Show('G');
// Call the version of the method that displays a decimal
exo.Show(355.65);
return 0;
}
}
This would produce:
246
G
355.65
Press any key to continue . . .
We passed a constant value directly to the method when we
called it. Remember that you can also first declare a variable, assign it a
value, and then pass that variable to the method. Here are examples:
public class Exercise
{
static int Main()
{
var exo = new Generator();
// Call the version of the method that displays an integer
var Value1 = 246;
exo.Show(Value1);
// Call the version of the method that displays a character
var Value2 = 'G';
exo.Show(Value2);
// Call the version of the method that displays a decimal
var Value3 = 355.65;
exo.Show(Value3);
return 0;
}
}
Although this is based on the concept of method overloading,
another way you can solve this type of problem is to create one method that
doesn't know the type of value that would be passed to it but the method is
equipped to process the value appropriately. Based on the above program, you can
create one method that takes an argument and it displays its value. To do this,
at the time you are defining the method, you only let it know that it would
receive an argument but you don't specify the type of value that it will
process. Such a method is referred to as generic.
Practical
Learning: Introducing Generics
|
|
- Start Microsoft Visual C# and create a new Console Application named
CommercialStore1
- To create a new class, on the main menu, click Project -> Add Class...
- Set the Name to StoreItem and press Enter
- Change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CommercialStore1
{
public class StoreItem
{
public class CItem
{
public double Item;
public CItem Next;
}
public CItem Head = null;
public int Size;
public int Count()
{
return Size;
}
public int Add(CItem NewItem)
{
CItem Sample = new CItem();
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
return Size++;
}
public CItem Retrieve(int Position)
{
CItem Current = Head;
for (int i = Count() - 1; i > Position && Current != null; i--)
{
Current = Current.Next;
}
return Current;
}
public void ShowItem(double item)
{
Console.WriteLine("Item: {0}", item);
}
}
}
|
- Access the Program.cs file and change it as follows:
using System;
namespace CommercialStore1
{
public class Program
{
static void Main()
{
StoreItem exo = new StoreItem();
StoreItem.CItem Part;
Part = new StoreItem.CItem();
Part.Item = 97.43;
exo.Add(Part);
Part = new StoreItem.CItem();
Part.Item = 274.87;
exo.Add(Part);
Part = new StoreItem.CItem();
Part.Item = 8.7873;
exo.Add(Part);
Part = new StoreItem.CItem();
Part.Item = 2764.4;
exo.Add(Part);
Part = new StoreItem.CItem();
Part.Item = 92.4662;
exo.Add(Part);
Part = new StoreItem.CItem();
Part.Item = 66800.85;
exo.Add(Part);
Console.WriteLine("-=- List of Items -=-");
for (int i = 0; i < exo.Count(); i++)
{
StoreItem.CItem One = exo.Retrieve(i);
exo.ShowItem(One.Item);
}
Console.WriteLine("\nNumber of Items: {0}\n", exo.Count());
}
}
}
|
- Execute the application to see the result
-=- List of Items -=-
Item: 97.43
Item: 274.87
Item: 8.7873
Item: 2764.4
Item: 92.4662
Item: 66800.9
Number of Items: 6
Press any key to continue . . .
|
- Close the DOS window
A generic method is a method that can process a value whose
type is known only when the variable is accessed. To create a generic method, on
the right side of the name of the method, type the <> operator. Inside of this
operator, enter a letter or a name, which is referred to as parameter type. Here
is an example:
public class Generator
{
public void Show<TypeOfValue>()
{
}
}
One of the ways you can use the parameter type is to pass an
argument to the method. You do this by preceding the name of the argument with
the parameter type. Here is an example:
public class Generator
{
public void Show<TypeOfValue>(TypeOfValue value)
{
}
}
In the body of the method, you can process the argument as
you see fit. At a minimum, and based on our earlier program, you can simply
display the value by passing it to the Console.WriteLine() method. Here
is an example:
public class Generator
{
public void Show<TypeOfValue>(TypeOfValue value)
{
Console.WriteLine(value);
}
}
By tradition, most programmers and most documents use the
letter T for the parameter type.
Practical
Learning: Creating a Generic Method
|
|
- To create a generic method, change the ShowItem() method as follows:
public void ShowItem<T>(T item)
{
Console.WriteLine("Item: {0}", item);
}
|
- Save the file
As mentioned earlier, one of the particularities of a
generic method is that, at the time it is defined, the method doesn't know the
type of the parameter. This means that, when calling the method, you must make
sure you clearly specify the type of value that will be processed. You can do
this by directly passing (a constant of) the type of value that the method will
process. Here are different examples of calling our Show() method:
using System;
public class Generator
{
public void Show<TypeOfValue>(TypeOfValue value)
{
Console.WriteLine(value);
}
}
public class Exercise
{
static int Main()
{
var exo = new Generator();
// Call the version of the function that displays an integer
var Value1 = 246;
exo.Show(Value1);
// Call the version of the function that displays a character
var Value2 = 'G';
exo.Show(Value2);
// Call the version of the function that displays a decimal
var Value3 = 355.65;
exo.Show(Value3);
return 0;
}
}
When complied and executed, this program would produce:
246
G
355.65
Press any key to continue . . .
As an alternative, you can type the name of the method,
followed by angle brackets. Inside of the brackets, enter the data type of the
value that will be processed. After the angle brackets, open the parentheses
and, inside of them, type the constant value that will be processed. Here are
examples:
using System;
public class Generator
{
public void Show<TypeOfValue>(TypeOfValue value)
{
Console.WriteLine(value);
}
}
public class Program
{
static int Main()
{
var exo = new Generator();
// Call the version of the function that displays an integer
var Value1 = 246;
exo.Show<int>(Value1);
// Call the version of the function that displays a character
var Value2 = 'G';
exo.Show<char>(Value2);
// Call the version of the function that displays a decimal
var Value3 = 355.65;
exo.Show<double>(Value3);
return 0;
}
}
You can also declare the value as a constant before passing
it to the method.
Practical
Learning: Calling a Generic Method
|
|
- To specify the parameter type of a generic method when calling it,
change the Main() method as follows:
class Program
{
static void Main()
{
. . .
Console.WriteLine("-=- List of Items -=-");
for (int i = 0; i < exo.Count(); i++)
{
Exercise.CItem One = exo.Retrieve(i);
exo.ShowItem<double>(One.Item);
}
Console.WriteLine("\nNumber of Items: {0}\n", exo.Count());
}
}
|
- Execute the application and notice that it works fine
- Close the DOS window
A Generic Method With Various Parameters
|
|
Just like a method can take one argument, it can take
various generic parameters. You can pass one argument as a known type and the
other as a generic type. Here is an example:
using System;
public class Generator
{
public void Show<TypeOfValue>(string msg, TypeOfValue value)
{
Console.WriteLine("{0}: {1}", msg, value);
}
}
public class Exercise
{
static int Main()
{
var exo = new Generator();
exo.Show<int>("Integer", 246);
exo.Show<char>("Character", 'G');
exo.Show<double>("Decimal", 355.65);
return 0;
}
}
This would produce:
Integer: 246
Character: G
Decimal: 355.65
Press any key to continue . . .
Although we directly passed the values to the method when
calling it, you can first declare a variable before passing it to the method.
Here are examples:
using System;
public class Generator
{
public void Show<TypeOfValue>(string msg, TypeOfValue value)
{
Console.WriteLine("{0}: {1}", msg, value);
}
}
public class Exercise
{
static int Main()
{
var exo = new Generator();
var message = "Integer";
const int iValue = 246;
exo.Show<int>(message, iValue);
message = "Character";
const char cValue = 'G';
exo.Show<char>(message, cValue);
message = "Decimal";
const double dValue = 355.65;
exo.Show<double>(message, dValue);
return 0;
}
}
Practical
Learning: Using a Method With Various Parameters
|
|
- Access the StoreItem.cs file
- To create and use a method with various parameters, make the following
changes:
namespace CommercialStore1
{
public class StoreItem
{
. . .
public void ShowItem<T>(string content, int index, T item)
{
Console.WriteLine("{0} {1}: {2}", content, index, item);
}
}
}
|
- Access the Program.cs file and change it as follows:
namespace CommercialStore1
{
class Program
{
static void Main()
{
. . .
for (int i = 0; i < exo.Count(); i++)
{
Exercise.CItem One = exo.Retrieve(i);
exo.ShowItem<double>("Item", i+1, One.Item);
}
Console.WriteLine("\nNumber of Items: {0}\n", exo.Count());
}
}
}
|
- Execute the application
-=- List of Items -=-
Item 1: 97.43
Item 2: 274.87
Item 3: 8.7873
Item 4: 2764.4
Item 5: 92.4662
Item 6: 66800.85
Number of Items: 6
Press any key to continue . . .
|
- Close the DOS window
A Generic Method With Various Parameter Types
|
|
As seen above, you can pass different arguments to a method.
You can also pass different parameter types, in any appropriate order of your
choice, to a method. To pass two parameter types to a method, inside its <>
operator, enter the names of two parameter types separated by a comma. Here is
an example:
public class Generator
{
public void Show<FirstType, SecondType>()
{
}
}
If you want to use the parameter types, you can pass an
argument for each to the method. Remember that each parameter type represents a
data type; so you can use it as the type of an argument. Here are examples:
public class Generator
{
public void Show<FirstType, SecondType>(FirstType first,
SecondType second)
{
}
}
In the body of the method, you can then use the arguments as
you see fit. For example, you can display their values by passing them to the
Console.WriteLine() method. Here is an example:
public class Generator
{
public void Show<FirstType, SecondType>(FirstType first,
SecondType second)
{
Console.WriteLine("First: {0}\nSecond: {1}\n", first, second);
}
}
Calling a Generic Method With Various Parameter
Types
|
|
To call a method that takes various parameters, you can
simply pass it the value of each argument. Here is an example:
using System;
public class Generator
{
public void Show<FirstType, SecondType>(FirstType first,
SecondType second)
{
Console.WriteLine("First: {0}\nSecond: {1}\n", first, second);
}
}
public class Exercise
{
static int Main()
{
var exo = new Generator();
var iValue = 246;
var message = "Some Message";
exo.Show(message, iValue);
return 0;
}
}
This would produce:
First: Some Message
Second: 246
Press any key to continue . . .
An alternative is to specify the type of each argument. To
do this, inside the <> operator on the right side of the name of the method,
enter the data types separated by a comma. Here are examples:
using System;
public class Generator
{
public void Show<FirstType, SecondType>(FirstType first,
SecondType second)
{
Console.WriteLine("First: {0}\nSecond: {1}\n", first, second);
}
}
public class Exercise
{
static int Main()
{
var exo = new Generator();
var iValue = 246;
var message = "Some Message";
exo.Show(message, iValue);
iValue = 85;
var cValue = 'G';
exo.Show<int, char>(iValue, cValue);
var weeklyHours = 42.50d;
var hourlySalary = 25.05;
exo.Show<double, double>(weeklyHours, hourlySalary);
return 0;
}
}
This would produce:
First: Some Message
Second: 246
First: 85
Second: G
First: 42.5
Second: 25.05
Press any key to continue . . .
Notice that the arguments can be of the same type or
different types. It is up to you to determine the type of a particular argument
when calling the method.
Like a method, a class can be created as a generic. When a
class is created as generic, it is asked to process a value wihtout knowing what
type that value is. This means that the class will known the type of value only
when it is called.
To create a generic class, on the right side of the name of
the class, type the <> operator and enter a name for the parameter type. Here is
an example:
public class Exercise<TypeOfValue>
{
}
This parameter type is just a representative of a data type.
As a data type, you can use it to declare a variable in the body of the class.
Here is an example:
public class Exercise<TypeOfValue>
{
public TypeOfValue value;
}
After declaring such a variable, you can use it in your
application. For example, you can access it outside of the class using the
period operator. Inside of the class, one way you can use the variable is to
display its value using one of the methods of the class. Here is an example:
public class Exercise<TypeOfValue>
{
public TypeOfValue value;
public void Show()
{
Console.WriteLine("Value: {0}\n", value);
}
}
Practical
Learning: Introducing Generic Classes
|
|
- To start a new program, on the main menu, click the File -> New Project
...
- Click Console Application. Set the Name to CommercialStore2 and
press Enter
- To create a new class, on the main menu, click Project -> Add Class...
- Set the Name to ListOfItems and click OK
- Change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CommercialStore2
{
public class ListOfItems
{
public class CItem
{
public double Item;
public CItem Next;
}
public ListOfItems()
{
Head = null;
Size = 0;
}
public CItem Head;
public int Size;
public int Count()
{
return Size;
}
public int Add(CItem NewItem)
{
CItem Sample = new CItem();
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
return Size++;
}
public CItem Retrieve(int Position)
{
CItem Current = Head;
for (int i = Count() - 1; i > Position && Current != null; i--)
{
Current = Current.Next;
}
return Current;
}
}
}
|
- Access the Program.cs file and change it as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CommercialStore2
{
public class Program
{
static void Main()
{
ListOfItems exo = new ListOfItems();
ListOfItems.CItem Part;
Part = new ListOfItems.CItem();
Part.Item = 97.43;
exo.Add(Part);
Part = new ListOfItems.CItem();
Part.Item = 274.87;
exo.Add(Part);
Part = new ListOfItems.CItem();
Part.Item = 8.7873;
exo.Add(Part);
Part = new ListOfItems.CItem();
Part.Item = 2764.4;
exo.Add(Part);
Part = new ListOfItems.CItem();
Part.Item = 92.4662;
exo.Add(Part);
Part = new ListOfItems.CItem();
Part.Item = 66800.85;
exo.Add(Part);
Console.WriteLine("-=- List of Items -=-");
for (int i = 0; i < exo.Count(); i++)
{
ListOfItems.CItem One = exo.Retrieve(i);
Console.WriteLine("Item: {0}", One.Item);
}
Console.WriteLine("\nNumber of Items: {0}\n", exo.Count());
}
}
}
|
- Execute the application and test it:
-=- List of Items -=-
Item: 97.43
Item: 274.87
Item: 8.7873
Item: 2764.4
Item: 92.4662
Item: 66800.85
Number of Items: 6
Press any key to continue . . .
|
- Close the DOS window
After creating a generic class, you can use it. One way to
do this, as we have learned in previous lessons, consists of declaring a
variable for it. In previous lessons, to declare a variable of a class, we would
write:
Exercise exo = new Exercise();
If the class is generic, on the right side, type the <>
operator. Inside of this operator, enter the data type that will be processed as
the parameter type of the generic class. Here is an example:
using System;
public class Generator<TypeOfValue>
{
public TypeOfValue value;
public void Show()
{
Console.WriteLine("Value: {0}\n", value);
}
}
public class Exercise
{
static int Main()
{
Generator<int> exo = new Generator<int>();
return 0;
}
}
You can also declare a variable of a generic type using the
var keyword. To do this, use var on the left side of the variable name, omit the
<> operator and the data type. This would be done as follows:
public class Exercise
{
static int Main()
{
var exo = new Generator<int>();
return 0;
}
}
After declaring the variable, you can then access the
member(s) of the class using the period operator. Here are examples:
using System;
public class Generator<TypeOfValue>
{
public TypeOfValue value;
public void Show()
{
Console.WriteLine("Value: {0}\n", value);
}
}
public class Exercise
{
static int Main()
{
var exo = new Generator<int>();
var iValue = 246;
exo.value = iValue;
exo.Show();
return 0;
}
}
Passing a Parameter Type to a Method
|
|
We saw that you could declare a variable of a parameter type
in the generic class. Another way you can use it is to pass it as an argument to
a method and make the argument a parameter type. As seen previously, you can use
the argument as you see fit. For example, you can display its value to the
console. Here is an example:
using System;
public class Generator<TypeOfValue>
{
public void Show(TypeOfValue value)
{
Console.WriteLine("Value: {0}\n", value);
}
}
public class Exercise
{
static int Main()
{
var exo = new Generator<int>();
var iValue = 246;
exo.Show(iValue);
return 0;
}
}
In the same way, you can pass the parameter type to a
constructor of the class. Here is an example:
public class Generator<TypeOfValue>
{
private TypeOfValue val;
public Exercise(TypeOfValue v)
{
val = v;
}
}
Returning a Parameter Type
|
|
Besides, or as opposed to, passing a parameter type, you can
create a method that returns a parameter type. Once again, you can primarily
observe the rules we reviewed for returning a value from a method. Here is an
example:
using System;
public class Generator<TypeOfValue>
{
private TypeOfValue val;
public Generator(TypeOfValue v)
{
val = v;
}
public TypeOfValue GetValue()
{
return val;
}
}
public class Exercise
{
static int Main()
{
var exo = new Generator<double>(35.65);
Console.WriteLine("Value: {0}\n", exo.GetValue());
return 0;
}
}
Practical
Learning: Returning a Parameter Type
|
|
- Open the ListOfItems.cs source file
- To apply what we have reviewed, change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CommercialStore2
{
public class ListOfItems
{
public class CItem<T>
{
public double Item;
public CItem<T> Next;
}
public ListOfItems()
{
Head = null;
Size = 0;
}
public CItem<double> Head;
public int Size;
public int Count()
{
return Size;
}
public int Add(CItem<double> NewItem)
{
CItem<double> Sample = new CItem<double>();
Sample = NewItem;
Sample.Next = Head;
Head = Sample;
return Size++;
}
public CItem<double> Retrieve(int Position)
{
CItem<double> Current = Head;
for (int i = Count() - 1; i > Position && Current != null; i--)
{
Current = Current.Next;
}
return Current;
}
}
}
|
- Access the Program file and change it as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CommercialStore2
{
public class Program
{
static void Main()
{
ListOfItems exo = new ListOfItems();
ListOfItems.CItem<double> Part;
Part = new ListOfItems.CItem<double>();
Part.Item = 97.43;
exo.Add(Part);
Part = new ListOfItems.CItem<double>();
Part.Item = 274.87;
exo.Add(Part);
Part = new ListOfItems.CItem<double>();
Part.Item = 8.7873;
exo.Add(Part);
Part = new ListOfItems.CItem<double>();
Part.Item = 2764.4;
exo.Add(Part);
Part = new ListOfItems.CItem<double>();
Part.Item = 92.4662;
exo.Add(Part);
Part = new ListOfItems.CItem<double>();
Part.Item = 66800.85;
exo.Add(Part);
Console.WriteLine("-=- List of Items -=-");
for (int i = 0; i < exo.Count(); i++)
{
ListOfItems.CItem<double> One = exo.Retrieve(i);
Console.WriteLine("Item: {0}", One.Item);
}
Console.WriteLine("\nNumber of Items: {0}\n", exo.Count());
}
}
}
|
- Execute the application and test it
- Close the DOS window
A Property of the Parameter Type
|
|
You can create a property that is of the parameter type of
the generic class. There is no significant rule to follow when creating the
property, except that you should remember that, at the time you are creating the
property, the class doesn't know the type of the parameter. Here is an example:
using System;
public class Generator<TypeOfValue>
{
private TypeOfValue val;
public TypeOfValue Value
{
get { return val; }
set { val = value; }
}
public void Show()
{
Console.WriteLine("Value: {0}\n", val);
}
}
public class Exercise
{
static int Main()
{
var exo = new Generator<int>();
exo.Value = 246;
exo.Show();
return 0;
}
}
A Generic Class With Multiple Parameters
|
|
Using Multiple Type Parameters
|
|
As done for generic methods, when creating a generic class,
you can specify more than one parameter type. To do this, in the <> operator,
after the first generic type, enter a comma and another generic type. Here is an
example:
public class Generator<T, V>
{
}
If you know for sure that the parameters will be of the same
type, you can use one method to process both. Otherwise, you can declare the
necessary members for each type. You can also create a method that would take
many arguments with each argument of a particular type. Here are examples:
using System;
public class Generator<T, V>
{
private T t;
private V v;
public void SetTValue(T value)
{
t = value;
}
public T GetTValue()
{
return t;
}
public void SetVValue(V value)
{
v = value;
}
public V GetVValue()
{
return v;
}
public void Show(T tValue, V vValue)
{
Console.WriteLine("First: {0}\nSecond: {1}", tValue, vValue);
}
}
When declaring a variable for the class, make sure you
appropriately specify the list of parameter types. Here are two examples:
public class Exercise
{
static int Main()
{
Generator<int, int> IntTypes = new Generator<int, int>();
IntTypes.SetTValue(246);
IntTypes.SetVValue(6088);
IntTypes.Show(IntTypes.GetTValue(), IntTypes.GetVValue());
Generator<double, double> DoubleTypes = new Generator<double, double>();
DoubleTypes.SetTValue(355.65);
DoubleTypes.SetVValue(1785.426);
DoubleTypes.Show(DoubleTypes.GetTValue(), DoubleTypes.GetVValue());
Generator<short, decimal> Disparate = new Generator<short, decimal>();
DoubleTypes.SetTValue(42);
DoubleTypes.SetVValue(245580.35);
DoubleTypes.Show(DoubleTypes.GetTValue(), DoubleTypes.GetVValue());
return 0;
}
}
You can also declare the variable using the var keyword. To
do this, on the left side of the assignment operator, type only the var keyword
and the name of the operator. Here is an example:
public class Exercise
{
static int Main()
{
var IntTypes = new Generator<int, int>();
IntTypes.SetTValue(246);
IntTypes.SetVValue(6088);
IntTypes.Show(IntTypes.GetTValue(), IntTypes.GetVValue());
var DoubleTypes = new Generator<double, double>();
DoubleTypes.SetTValue(355.65);
DoubleTypes.SetVValue(1785.426);
DoubleTypes.Show(DoubleTypes.GetTValue(), DoubleTypes.GetVValue());
var Disparate = new Generator<short, decimal>();
DoubleTypes.SetTValue(42);
DoubleTypes.SetVValue(245580.35);
DoubleTypes.Show(DoubleTypes.GetTValue(), DoubleTypes.GetVValue());
return 0;
}
}
This would produce:
First: 246
Second: 6088
First: 355.65
Second: 1785.426
First: 42
Second: 245580.35
Press any key to continue . . .
If a generic class has more than one parameter type, they
don't have to be of the same type. At the time you are creating the class, you
may not specify their types but you can anticipate that they would be different.
It is when you declare the variable that you would need to determine their
precise types.
Even if the parameters are of primitive types, you can first
declare the variables and pass them to the class.
A Class as a Parameter Type
|
|
So far, in our examples, we treated the parameter type as a
primitive data type. A parameter type can also be a formal class, either one
that you created yourself or one that exists as part of the C# language. When
creating the generic class, you must follow all the rules we have reviewed so
far for generic classess. Here is such a simple class:
public class Generator
{
public void Show(TypeOfValue val)
{
Console.WriteLine("{0}\n", val.ToString());
}
}
As mentioned already, the class that would be processed by
the generic one must have been previously created so it can be used as a
parameter. When declaring a variable of the generic class, make sure you enter
the name of the normal class in place of the parameter type. Everything else is
as we have done so far. Here is an example:
using System;
public class FourSideGeometricFigure
{
private string nm;
private double bs;
private double hg;
public string Name
{
get { return nm; }
set { nm = value; }
}
public double Base
{
get { return bs; }
set { bs = value; }
}
public double Height
{
get { return hg; }
set { hg = value; }
}
public double Area
{
get { return bs * hg; }
}
public override string ToString()
{
string result = "Type: " + nm + "\n" +
"Base: " + bs.ToString() + "\n" +
"Height: " + hg.ToString() + "\n" +
"Area: " + Area.ToString();
return result;
}
}
public class Generator<TypeOfValue>
{
public void Show(TypeOfValue val)
{
Console.WriteLine("{0}\n", val.ToString());
}
}
public class Exercise
{
static int Main()
{
var sqr = new FourSideGeometricFigure();
sqr.Name = "Square";
sqr.Base = 36.82;
sqr.Height = 36.82;
Generator<FourSideGeometricFigure> exoSquare =
new Generator<FourSideGeometricFigure>();
exoSquare.Show(sqr);
FourSideGeometricFigure rect = new FourSideGeometricFigure();
rect.Name = "Rectangle";
rect.Base = 52.94;
rect.Height = 27.58;
Generator<FourSideGeometricFigure> exoRect =
new Generator<FourSideGeometricFigure>();
exoRect.Show(rect);
return 0;
}
}
You can also declare the variable using the var keyword.
Here are examples:
public class Exercise
{
static int Main()
{
var sqr = new FourSideGeometricFigure();
sqr.Name = "Square";
sqr.Base = 36.82;
sqr.Height = 36.82;
var exoSquare = new Generator<FourSideGeometricFigure>();
exoSquare.Show(sqr);
FourSideGeometricFigure rect = new FourSideGeometricFigure();
rect.Name = "Rectangle";
rect.Base = 52.94;
rect.Height = 27.58;
var exoRect = new Generator<FourSideGeometricFigure>();
exoRect.Show(rect);
return 0;
}
}
This would produce:
Type: Square
Base: 36.82
Height: 36.82
Area: 1355.7124
Type: Rectangle
Base: 52.94
Height: 27.58
Area: 1460.0852
Press any key to continue . . .
In the same way, you can create a generic class that takes more than one
parameter
Generic Classes and Inheritance
|
|
Consider the following geometric figures:
|
|
|
|
Square |
Rectangle |
Trapezoid |
Parallelogram |
Notice that these are geometric figures with each having
four sides. From what we know so far, we can create a base class to prepare it
for inheritance. If the class is very general, we can make it a generic one. We
can set a data type as an unknown type, anticipating that the dimensions of the
figure can be considered as integer or double-precision types. Here is an
example:
using System;
public class Quadrilateral<T>
{
protected T _base;
protected T _height;
protected string _name;
public virtual T Base
{
get { return _base; }
set { _base = value; }
}
public virtual T Height
{
get { return _height; }
set { _height = value; }
}
public virtual string Name
{
get { return _name; }
set { _name = value; }
}
public Quadrilateral()
{
_name = "Quadrilateral";
}
public Quadrilateral(string name)
{
_name = "Quadrilateral";
}
public Quadrilateral(T bs, T height)
{
_name = "Quadrilateral";
_base = bs;
_height = height;
}
public Quadrilateral(string name, T bs, T height)
{
_name = name;
_base = bs;
_height = height;
}
public virtual string Describe()
{
return "A quadrilateral is a geometric figure with four sides";
}
public virtual void ShowCharacteristics()
{
Console.WriteLine("Geometric Figure: {0}", Name);
Console.WriteLine("Description: {0}", Describe());
Console.WriteLine("Base: {0}", Base);
Console.WriteLine("Height: {0}", Height);
}
}
public class Exercise
{
static int Main()
{
// Trapezoid with equal sides
var Kite = new Quadrilateral<double>("Beach Kite", 18.64, 18.64);
Kite.ShowCharacteristics();
Console.WriteLine();
// Rectangle, in meters
var BasketballStadium = new Quadrilateral<Byte>();
BasketballStadium.Name = "Basketball Stadium";
BasketballStadium.Base = 15;
BasketballStadium.Height = 28;
BasketballStadium.ShowCharacteristics();
Console.WriteLine();
return 0;
}
}
This would produce:
Geometric Figure: Beach Kite
Description: A quadrilateral is a geometric figure with four sides
Base: 18.64
Height: 18.64
Geometric Figure: Basketball Stadium
Description: A quadrilateral is a geometric figure with four sides
Base: 15
Height: 28
Press any key to continue . . .
If you have a generic class that can serve as a foundation
for another class, you can derive one class from the generic one. To do this,
use the formula we apply when deriving a class but follow the name of each class
with <>. Inside of the <> operator, enter the same identifier to indicate that
the class is a generic type that is based on another generic class. Here is an
example:
public class Square<T> : Quadrilateral<T>
{
}
In the body of the new class, you can use the parameter type
as you see fit. For example, you can declare some member variables of that type.
You can create methods that return the parameter type or you can pass arguments
of the parameter type. When implementing the methods of the new class, use the
member variables of the parameter and the argument(s) based on the parameter
type as you see fit. You can then declare a variable of the class and use it as
we done so far for other generic classes. Here is an example:
using System;
public class Quadrilateral<T>
{
protected T _base;
protected T _height;
protected string _name;
public virtual T Base
{
get { return _base; }
set { _base = value; }
}
public virtual T Height
{
get { return _height; }
set { _height = value; }
}
public virtual string Name
{
get { return _name; }
set { _name = value; }
}
public Quadrilateral()
{
_name = "Quadrilateral";
}
public Quadrilateral(string name)
{
_name = "Quadrilateral";
}
public Quadrilateral(T bs, T height)
{
_name = "Quadrilateral";
_base = bs;
_height = height;
}
public Quadrilateral(string name, T bs, T height)
{
_name = name;
_base = bs;
_height = height;
}
public virtual string Describe()
{
return "A quadrilateral is a geometric figure with four sides";
}
public virtual void ShowCharacteristics()
{
Console.WriteLine("Geometric Figure: {0}", Name);
Console.WriteLine("Description: {0}", Describe());
Console.WriteLine("Base: {0}", Base);
Console.WriteLine("Height: {0}", Height);
}
}
public class Square<T> : Quadrilateral<T>
{
public Square()
{
_name = "Square";
}
public Square(string name)
{
_name = "Square";
}
public Square(T side)
{
_name = "Square";
_base = side;
_height = side;
}
public Square(string name, T side)
{
_name = name;
_base = side;
_height = side;
}
public override string Describe()
{
return "A square is a quadrilateral with four equal sides";
}
public override void ShowCharacteristics()
{
Console.WriteLine("Geometric Figure: {0}", Name);
Console.WriteLine("Description: {0}", Describe());
Console.WriteLine(" {0}", Describe());
Console.WriteLine("Side: {0}", Base);
}
}
public class Exercise
{
static int Main()
{
// Rectangle, in meters
var plate = new Square<Byte>();
plate.Name = "Plate";
plate.Base = 15;
plate.Height = 28;
plate.ShowCharacteristics();
Console.WriteLine();
return 0;
}
}
This would produce:
Geometric Figure: Plate
Description: A quadrilateral is a geometric figure with four sides
A square is a quadrilateral with four equal sides
Side: 15
Press any key to continue . . .
Generic Classes and Interfaces
|
|
As done for a generic class, you can create a generic
interface that would serve as the base for generic classes. To proceed, when
creating the interface, follow its name with a <> declaration and, inside
of the <> operator, enter an identifier for the parameter type. Here is an
example:
public interface IGeometry<T>
{
string Name { get; set; }
void Display();
}
Since this is a generic interface, like an interface class,
when deriving a class from it, follow the formula we reviewed for inheriting
from a generic class. Here is an example:
using System;
public interface IGeometry<T>
{
string Name { get; set; }
void Display();
}
public class Round<T> : IGeometry<T>
{
}
When implementing the derived class, you must observe all
rules that apply to interface derivation. Here is an example:
using System;
public interface IGeometry<T>
{
string Name { get; set; }
void Display();
}
public class Round<T> : IGeometry<T>
{
private string _name;
public Round()
{
_name = "Unknown";
}
public Round(string name)
{
_name = name;
}
public virtual string Name
{
get { return _name; }
set { _name = value; }
}
public virtual void Display()
{
Console.WriteLine("Name: {0}", Name);
}
}
public class Exercise
{
static int Main()
{
var rnd = new Round<decimal>();
rnd.Name = "General Round Shape";
rnd.Display();
Console.WriteLine();
return 0;
}
}
This would produce:
Name: General Round Shape
Press any key to continue . . .
In the same way, you can derive a generic class from another
generic class that derived from a generic interface.
Constraining a Generic
Class
|
|
Imagine you create a regular interface such as the
following:
public interface IGeometry
{
string Name { get; set; }
void Display();
}
Then imagine you derive a regular class from it. Here is an
example:
using System;
public interface IGeometry
{
string Name { get; set; }
void Display();
}
public class Round : IGeometry
{
private string _name;
private double _rad;
public Round()
{
_name = "Unknown";
}
public Round(string name)
{
_name = name;
_rad = 0.00;
}
public Round(string name, double radius)
{
_name = name;
_rad = radius;
}
public virtual string Name
{
get { return _name; }
set { _name = value; }
}
public double Radius
{
get { return _rad; }
set
{
_rad = (value <= 0) ? 0.00 : value;
}
}
public virtual void Display()
{
Console.WriteLine("Name: {0}", Name);
Console.WriteLine("Radius: {0}", Radius);
}
}
public class Exercise
{
static int Main()
{
var rnd = new Round();
rnd.Name = "General Round Shape";
rnd.Radius = 38.24;
rnd.Display();
Console.WriteLine();
return 0;
}
}
You may be tempted to derive just any type of class from it.
One of the features of generics is that you can create a class that must
implement the functionality of a certain abstract class of your choice. For
example, when creating a generic class, you can oblige it to implement the
functionality of a certain interface or you can make sure that the class is
derived from a specific base class. This would make sure that the generic class
surely contains some useful functionality.
To create a constraint on a generic
class, after the <TypeName> operator, type where
TypeName : followed by the rule that the class must follow. For example, you
may want the generic class to implement the functionality of a pre-defined
class. You can create the generic class as follows:
public interface IGeometry
{
}
public class Round : IGeometry
{
}
public class Sphere<T>
where T : Round
{
}
After creating the class, you must implement the virtual
members of the where class/interface, using the rules of generic classes,
the way we have done it so far. When declaring a variable for the generic class,
in its <> operator, you must enter an object of the base class. Here is an
example:
using System;
public interface IGeometry
{
string Name { get; set; }
void Display();
}
public class Round : IGeometry
{
private string _name;
private double _rad;
public Round()
{
_name = "Unknown";
}
public Round(string name)
{
_name = name;
_rad = 0.00;
}
public Round(string name, double radius)
{
_name = name;
_rad = radius;
}
public virtual string Name
{
get { return _name; }
set { _name = value; }
}
public double Radius
{
get { return _rad; }
set
{
_rad = (value <= 0) ? 0.00 : value;
}
}
public virtual void Display()
{
Console.WriteLine("Name: {0}", Name);
Console.WriteLine("Radius: {0}", Radius);
}
}
public class Sphere<T>
where T : Round
{
private T _t;
public Sphere() { }
public Sphere(T fig)
{
_t = fig;
}
public T Figure
{
get { return _t; }
set { _t = value; }
}
}
public class Exercise
{
static int Main()
{
var rnd = new Round();
rnd.Name = "Circle";
rnd.Radius = 60.12;
Sphere<Round> sph = new Sphere<Round>();
sph.Figure = rnd;
Console.WriteLine("Circle Characteristics");
Console.WriteLine("Name: {0}", sph.Figure.Name);
Console.WriteLine("Radius: {0}", sph.Figure.Radius);
Console.WriteLine();
return 0;
}
}
This would produce:
Circle Characteristics
Name: Circle
Radius: 60.12
Press any key to continue . . .
You can also create a constraint so that a generic class
implements an interface.
|