Introduction
Generics (in the "System.Collections.Generic" namespace) were introduced in the 2.0 version of .Net and are now widely used. The concept is similar to C++ templates but different in implementation and capabilities. It is a very important feature of .Net programming, allowing a class and methods such as lists, hash tables, queues and so on to be defined with a type T as a parameter.
The type of generic parameter is specified only at the time of declaration. Using this, the programmer will improve the performance of an application. In addition to performance, generics provide type-safety and higher quality code because you get to reuse data processing algorithms without duplicating type-specific code.
Generics are also known as Parametric polymorphism.
Example
You can write a single class of generic type and we can use that generic class just by applying the appropriate datatype. For example I create a class MyClass<T> and we can use it like MyClass<int>, MyClaas<String>, MyClass<double> or MyClass< AnyClass> without the need for casting and unboxing. For examle, consider a scenario where we need a different kind of queue, like a queue of int, string so we can create a generic type queue and based on our needs we can use that.
Advantages of using generic
ArrayList dynamically resizes. As elements are added, it grows in capacity to accommodate them. It is most often used in older C# programs. It stores a collection of elements of type object. Casting is needed. ArrayList is present in the System.Collections namespace.
Generics provide a solution for the limitation of an ArrayList collection in the Common Language Runtime. We will see the limitations of non-generic collection classes, using the ArrayList collection class.
using System;
using System.Collections;
public class ArrayListExample
{
static void ArrayListMethod()
{
// Creates and initializes a new ArrayList.
ArrayList listExample = new ArrayList();
listExample.Add("One");
listExample.Add("2");
listExample.Add(3);
}
}
In the ArrayList Collection, any reference or value type data added to an ArrayList must be typecast to "System.Object". If the items are value types then they must be boxed when they are added to the list and unboxed when they are retrieved. The casting, boxing, unboxing operation reduce the performance.
In a generic List<T> collection, using the "System.Collections.Generic" namespace, we will see the same operation.
using System;
using System.Collections.Generic;
public class GenericList
{
public static void GenericListMethod()
{
List<int> genericList = new List<int>();
// No boxing, no casting:
genericList.Add(12);
genericList.Add(13);
genericList.Add(14);
genericList.Add(15);
}
}
As compared to ArrayList it would be safer and faster, because in ArrayList we can enter anything since it accepts the value of object type. Here we can only enter type specific data like int, string or double.
- Code Reusability in generics (Advantage)
Generics provide type-safe code with re-usability.
Example
Suppose you need to sort the integer and floating type numbers, let's see how to do it in collections and generics.
The following shows how to do it in a collection:
using System.Collections;
public class GenericArrayList
{
public static void ListSorting()
{
int[] intArray = { 8, 10, 2, 6, 3 };
// Sort your int array
Array.Sort(intArray);
foreach (var i in intArray)
{
Console.WriteLine(i);
}
// Sort it the other way
string[] strArray = { "A", "D", "C", "E", "B" };
Array.Sort(strArray);
foreach (var i in strArray)
{
Console.WriteLine(i);
}
Console.ReadLine();
}
}
The following shows how to do it using Generics:
using System.Collections.Generic;
public class ArrayList
{
private static object[] Sort<T1>(object[] iInputeArray)
{
array.Sort(iInputeArray);
return iInputeArray;
}
}
Here T is a type. Once we create this method, we can call it with various data types as follows.
In this way a Generic provides code re-usability.
public static void SortList()
{
object[] iInputArray = { 3, 5, 8, 6, 10, 6, 2, 1, 12 };
iInputArray = Sort<int>(iInputArray);
foreach (Object obj in iInputArray)
Console.Write(" {0}", obj);
object[]strInputArray = { "A" ,"C", "T", "R", "E", "D" };
strInputArray = Sort<string>(strInputArray);
foreach (Object obj in strInputArray)
Console.Write(" {0}", obj);
Console.WriteLine();
Console.ReadLine();
}
Benefits
The following are the benefits of generics:
- There is no need for casting for accessing the elements of the data.
- Code is not duplicated for multiple types of data.
- Generics can hold the data with the same type and we can decide what type of data that the collection holds.
- You can create your own generic interface, classes, method, events and delegate.
Why to use Generics
There are mainly two reasons to use generics as in the following:
- Performance: Collections that store the objects uses boxing and unboxing on data types. A collection can reduce the performance.
By using generics it helps to improve the performance and type safety.
- Type Safety: there is no strong type information at compile time as to what it is stored in the collection.
When to use Generics
- When you use various #ff0000 data types, you need to create a generic type.
- It is easier to write code once and reuse it for multiple types.
- If you are working on a value type then for that boxing and unboxing operation will occur, Generics will eliminate the boxing and unboxing operations.
Boxing: Conversion of a value type into a reference type of variable. When the variable of a value type is to be converted to a reference type, the object box is allocated to hold the value and copies the value into a box.
Unboxing: It is just the opposite of boxing.
Example Boxing/Unboxing
class BoxUnbox
{
Static void Main ()
{
Int i=1;
Object o=i; //boxing
Int j = (int) o; //unboxing
}
}
Generic Class
The common use of a generic class is with collections like a linked list, hash table, stack, queue and tree. The addition and removal of an item from a collection is basically the same.
Example
using System.Collections.Generic;
namespace Generic
{
public class ArrayClass<T>
{
object Data;
public void Push(object Obj)
{
Data= Obj;
}
public object Pop()
{
return Data;
}
}
}
Here T is a type of parameter. We can pass any data type (int, string and so on) as a parameter.
This class can be used as below.
public class SubClass
{
public static void MyClass()
{
ArrayClass<int> intArray = new ArrayClass<int>();
intArray.Push(10);
object intReturnValue = intArray.Pop();
Console.Write(" {0}", intReturnValue);
ArrayClass<string> strArray = new ArrayClass<string>();
strArray.Push("Hello word");
object strReturnValue = strArray.Pop();
Console.Write(" {0}", strReturnValue);
Console.ReadLine();
}
}
Generic Methods
Generic methods are a method declared with type parameters.
Examples
using System.Collections.Generic;
public class ArrayList
{
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
}
The following method shows how to call the method above.
public static void TestSwap()
{
int a = 1;
int b = 2;
Swap<int>(ref a, ref b);
System.Console.WriteLine(a + " " + b);
Console.ReadLine();
}