When we think about the word Generic outside of the programming world it simply means that the object is not tied to any specific kind. An example is a bank account. We may not know which bank it is associated too, if it is a checking or savings account, however we do know that we can generally deposit or withdrawal from one. Therefore we agree on the standard function and properties of a bank account, but perhaps don’t know all the specifics.
Generics has the similar context. Meaning that a class is not related to any specific type (bank, savings, checking, investment), but we still want it to do what the class should do (give us money).
Generics is an older term (in internet years anyway) and in my opinion, you probably wouldn’t want to implement something like this because in the newer versions of .Net you are provided with List, SortedList, Dictionary, ArrayList, etc. Most are found within the System.Collections .Net namespace. However, in your quest for a total understanding of C# and/or programming concepts, I can recommend at least understanding what is happening ‘behind the scenes’. Because List, SortedList, Dictionary, etc. implement the IEnumerable interface and are therefore using what is described here. It has just been abstracted away for simplicity reasons.
In this example we will create a GenericList class:
[sourcecode language="csharp" padlinenumbers="true" autolinks="false" gutter="false" toolbar="false"] public class GenericsList<t> : IEnumerable<t> { protected Element head; protected Element current = null; protected class Element { public Element nextElement {get; set;} public T elementData { get; set; } public Element(T t) { nextElement = null; elementData = t; } } public GenericsList() { head = null; } public void AddElementToList(T t) { Element element = new Element(t); element.nextElement = head; head = element; } public IEnumerator<t> GetEnumerator() { Element current = head; while (current != null) { yield return current.elementData; current = current.nextElement; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } [/sourcecode]
The above class provides the framework for for adding and reading the data elements within the list. For example, the AddElementToList(T) adds the element to a list. If it is the first element then the Element.nextElement is equal to NULL. This will tell us when we have have reached the last record in the list. We will generally read the elements from within a foreach statement. The IEnumerator GetEnumerator() method provides this capability for us. Since the release of .Net 2.0, we are no longer required to implement a Current or MoveNext method.
You can think of a GenericList as a Russian Matryoshka doll. I.e. a set of dolls of graduated size, each one fitting inside the next larger doll. As this picture illustrates. Element data is stored, then an instance of the next element is stored within itself, so on and so on and so on. Approach it from starting with the smallest doll being put into the next larger doll, so on and so on and so on.
We will next create a simple BankBalance class. This class provides the structure of the elements we store in the list.
[sourcecode language="csharp" autolinks="false" gutter="false" toolbar="false"] public class BankBalance { string accountNumber; double accountBalance; public BankBalance(string acctNum, double acctBal) { accountNumber = acctNum; accountBalance = acctBal; } public override string ToString() { return accountNumber + "\t:\t" + accountBalance; } } [/sourcecode]
Lastly, we will create the Main program that will:
1. Provide the data for our BankBalance class
2. Load the data into a GenericList of type BankBalance (ADD)
3. Write the data to the console via a foreach statement (READ)
[sourcecode language="csharp" autolinks="false" gutter="false" toolbar="false"] class GenericsProgram { static void Main(string[] args) { GenericsList<bankbalance> list = new GenericsList<bankbalance>(); //Create accountNumber and accountBalance //values to initialize BankBalance objects. string[] accountNumber = new string[] { "A12345-98", "B34565-64", "L98756-32" }; double[] accountBalance = new double[] { 125.12, 748.54, 42343.56 }; //Populate the list. for (int row = 0; row < accountNumber.Length; row++) { list.AddElementToList(new BankBalance(accountNumber[row], accountBalance[row])); } Console.WriteLine("Bank Account Balance List:"); foreach (BankBalance b in list) { Console.WriteLine(b.ToString()); } Console.ReadLine(); } } [/sourcecode]
Download the source here.
The Generics concepts is one of the more powerful tools you can use when managing data or in memory states of objects. They allow the programmer to store groups of similar data elements together in a type safe and very efficient (performance aware) format.