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> /// 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() + "..."; } }