I found a good Generics example in C# Cookbook and thought should share. It demonstrate a good use of strong typing and inner classes. I think I'm in compliance with O'Reilly Policy on Re-Use of Code Examples from Books
Understanding generic class types
public static void TestGenericClassInstanceCounter()
{
// regular class
StandardClass A = new StandardClass(5);
Console.WriteLine(A);
StandardClass B = new StandardClass(5);
Console.WriteLine(B);
StandardClass C = new StandardClass(5);
Console.WriteLine(C);
// generic class
GenericClass<bool> gA = new GenericClass<bool>(5);
Console.WriteLine(gA);
GenericClass<int> gB = new GenericClass<int>(5);
Console.WriteLine(gB);
GenericClass<string> gC = new GenericClass<string>(5);
Console.WriteLine(gC);
GenericClass<string> gD = new GenericClass<string>(5);
Console.WriteLine(gD);
bool b1 = true;
bool b2 = false;
bool bHolder = false;
// add to the standard class (as object)
A.AddItem(b1);
A.AddItem(b2);
// add to the generic class (as bool)
gA.AddItem(b1);
gA.AddItem(b2);
Console.WriteLine(A);
Console.WriteLine(gA);
// have to cast or get error CS0266:
// Cannot implicitly convert type 'object' to 'bool'...
bHolder = (bool)A.GetItem(1);
// no cast necessary
bHolder = gA.GetItem(1);
int i1 = 1;
int i2 = 2;
int i3 = 3;
int iHolder = 0;
// add to the standard class (as object)
B.AddItem(i1);
B.AddItem(i2);
B.AddItem(i3);
// add to the generic class (as int)
gB.AddItem(i1);
gB.AddItem(i2);
gB.AddItem(i3);
Console.WriteLine(B);
Console.WriteLine(gB);
// have to cast or get error CS0266:
// Cannot implicitly convert type 'object' to 'int'...
iHolder = (int)B.GetItem(1);
// no cast necessary
iHolder = gB.GetItem(1);
string s1 = "s1";
string s2 = "s2";
string s3 = "s3";
string sHolder = "";
// add to the standard class (as object)
C.AddItem(s1);
C.AddItem(s2);
C.AddItem(s3);
// add an int to the string instance, perfectly OK
C.AddItem(i1);
// add to the generic class (as string)
gC.AddItem(s1);
gC.AddItem(s2);
gC.AddItem(s3);
// try to add an int to the string instance, denied by compiler
// error CS1503: Argument '1': cannot convert from 'int' to 'string'
//gC.AddItem(i1);
Console.WriteLine(C);
Console.WriteLine(gC);
// have to cast or get error CS0266:
// Cannot implicitly convert type 'object' to 'string'...
sHolder = (string)C.GetItem(1);
// no cast necessary
sHolder = gC.GetItem(1);
// try to get a string into an int, error
// error CS0029: Cannot implicitly convert type 'string' to 'int'
//iHolder = gC.GetItem(1);
}
public class StandardClass
{
// static counter hangs off of the Type for
// StandardClass
static int _count = 0;
// create an array of typed items
int _maxItemCount;
object[] _items;
int _currentItem = 0;
// constructor that increments static counter
public StandardClass(int items)
{
_count++;
_maxItemCount = items;
_items = new object[_maxItemCount];
}
/// <summary>
/// Add an item to the class whose type
/// is unknown as only object can hold any type
/// </summary>
/// <param name="item">item to add</param>
/// <returns>the index of the item added</returns>
public int AddItem(object item)
{
if (_currentItem < _maxItemCount)
{
_items[_currentItem] = item;
return _currentItem++;
}
else
throw new Exception("Item queue is full");
}
/// <summary>
/// Get an item from the class
/// </summary>
/// <param name="index">the index of the item to get</param>
/// <returns>an item of type object</returns>
public object GetItem(int index)
{
Debug.Assert(index < _maxItemCount);
if (index >= _maxItemCount)
throw new ArgumentOutOfRangeException("index");
return _items[index];
}
/// <summary>
/// The count of the items the class holds
/// </summary>
public int ItemCount
{
get { return _currentItem; }
}
/// <summary>
/// ToString override to provide class detail
/// </summary>
/// <returns>formatted string with class details</returns>
public override string ToString()
{
return "There are " + _count.ToString() +
" instances of " + this.GetType().ToString() +
" which contains " + _currentItem + " items of type " +
_items.GetType().ToString() + "...";
}
}
public class GenericClass<T>
{
// static counter hangs off of the
// instantiated Type for
// GenericClass
static int _count = 0;
// create an array of typed items
int _maxItemCount;
T[] _items;
int _currentItem = 0;
// constructor that increments static counter
public GenericClass(int items)
{
_count++;
_maxItemCount = items;
_items = new T[_maxItemCount];
}
/// <summary>
/// Add an item to the class whose type
/// is determined by the instantiating type
/// </summary>
/// <param name="item">item to add</param>
/// <returns>the zero-based index of the item added</returns>
public int AddItem(T item)
{
if (_currentItem < _maxItemCount)
{
_items[_currentItem] = item;
return _currentItem++;
}
else
throw new Exception("Item queue is full");
}
/// <summary>
/// Get an item from the class
/// </summary>
/// <param name="index">the zero-based index of the item to get</param>
/// <returns>an item of the instantiating type</returns>
public T GetItem(int index)
{
Debug.Assert(index < _maxItemCount);
if (index >= _maxItemCount)
throw new ArgumentOutOfRangeException("index");
return _items[index];
}
/// <summary>
/// The count of the items the class holds
/// </summary>
public int ItemCount
{
get { return _currentItem; }
}
/// <summary>
/// ToString override to provide class detail
/// </summary>
/// <returns>formatted string with class details</returns>
public override string ToString()
{
return "There are " + _count.ToString() +
" instances of " + this.GetType().ToString() +
" which contains " + _currentItem + " items of type " +
_items.GetType().ToString() + "...";
}
}