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;
namespace Lessons
{
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);
}
}
class Program
{
static int Main()
{
// Rectangle, in meters
Square<Byte> 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()
{
Round<decimal> 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()
{
Round 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:
using System;
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()
{
Round 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.