Generics Generics are used to help make the code in the software components much more reusable. They are a type of data structure that contains code that remains the same. The data type of the parameters can change with each use.The usage within the data structure adapts to the different data type of the passed variables. Each time the generic is used, it can be customized for different data types without needing to rewrite any of the internal code. Generics permit classes, structs, interfaces, delegates, and methods to be parameterized by the types of data they store and manipulate. We can refer to a class, where we don't force it to be related to any specific Type, but we can still perform work with it in a Type-Safe manner. An example where we could implement Generics is in dealing with collections of items (integers, strings, Orders etc.). We can create a generic collection than can handle any Type in a generic and Type-Safe manner. For example, we can have a single array class to store a list of Users or even a list of Items, and when we actually use it, we will be able to access the items in the collection directly as a list of Users or Items, and not as objects (with boxing/unboxing, casting).
Generics Implementation Let us explore an example to understand the need for Generics and the Implementation part of it. Normally we write the Arraylistclass as: class MyArrayList { private object[] items; private int count=0; ... public void Add(object item) { items[count++] = item; } public object GetItem(int index) { return items[index]; } }
In this code, any untyped object can be added to the list and be read. While adding an untyped object is possible in a direct manner , there has to be an explicit type conversion on a read access. The untyped declaration of the list results in two problems.
The compiler has no chance to verify the content of the list and the necessary type conversions. Type failures will be recognized only at runtime-or maybe never recognized at all. You can solve both problems by using typed classes. The base class library provides an abstract base class, CollectionBase in the System.Collections namespace, that will enable you to create typed collections easily. You have to implement the body for the different methods and the indexer. Internally, the objects are stored in an untyped ArrayList, and calls are forwarded to this class. For reference types, this approach works very well, although a new class has to be explicitly developed for each data type. However, collections for value types created in this way are inefficient, because the data needs to be (un)boxed to be stored in the ArrayList internally. The solution for problems like this is the use of generic classes. A blueprint of the class is created just once. Instead of using a particular data type or object, a specific placeholder is added. // Defining a Generic Class class MyArrayList { private ItemType[] items; private int count; ... public void Add(ItemType item) { items[count] = item; } public ItemType GetItem(int index) { return items[index]; }
The class MyArrayList can be specialized for any data-type which would, later in the class, be referenced using the name ItemType class MyArrayList We replaced the data type of items with ItemType. Now we can utilize MyArrayList for various types. For example, the code MyArrayList iList = new MyArrayList();
Will create an instance of MyArrayList class that accepts and return only integers or that has replaced ItemType in class definition with int. Now we can only add and retrieve integers from iList. static void Main() { MyArrayList iList = new MyArrayList(); iList.Add(25); int iValue2 = iList.GetItem(1);
}
Similarly for user defined type 'Employee' static void Main() { MyArrayList pList = new MyArrayList(); pList.Add(new Employee("John")); }
Using Multiple Types We can define more than one type in Generic Definition. A practical example is a dictionary that can be typed individually on both the key and the value. In this case, it allows multiple placeholders. They have to be specified in angle brackets, separated by commas. public class MyDictionary { public void Add(KeyType key, ValueType value) { // ... } public ValueType this[KeyType key] { get { return ValueType.default; } } }
Although using Generics is type safe, you don't have type-safe access while developing the class itself. Because the type with which the generic class is used later is absolutely unknown, it's internally assumed to be object. Specific members of the data type can only be accessed after an explicit and therefore unsafe conversion. Possible failures will only be detected at run time.
Using Methods Methods are another exciting field of use for Generics. Generic methods will allow you to pass one or more data types. An Example is given below. public class MyClass { protected ItemType MyMethod(ItemType item) { return item; } }
Conclusion
Generics are very important and useful if you work, for example, with any kind of collections. Because of the backwards compatibility of ASP.NET 2.0, the existing collections couldn't be modified. Instead, a new namespace named System.Collections.Generic was created. It contains a lot of generic classes, structures, and interfaces like the following: Dictionary List Queue SortedDictionary Stack In the case of C#, generics are declared and type checked at compile time while instantiated at runtime just like any other object. C#Generics has the following advantages: 1. The Program becomes statically typed, so errors are discovered at compile-time. 2. No runtime casts are required and the program runs faster. 3. Primitive type values (e.g int) need not be wrapped. Hence the program is faster and uses less space. Reference : ASP.NET 2.0 Revealed, by Patrick Lorenz.