Generics in C#

Generics introduced in C# 2.0. It allows you to define a class with placeholders for the type of its fields, methods, parameters, etc. Generics replace these placeholders with some specific type at compile time.

A generic class can be defined using angle brackets <>. For example, the following is a simple generic class with a generic member variable, generic method and property.

Example: Generic class
class MyGenericClass<T>
{
    private T genericMemberVariable;

    public MyGenericClass(T value)
    {
        genericMemberVariable = value;
    }

    public T genericMethod(T genericParameter)
    {
        Console.WriteLine("Parameter type: {0}, value: {1}", typeof(T).ToString(),genericParameter);
        Console.WriteLine("Return type: {0}, value: {1}", typeof(T).ToString(), genericMemberVariable);
            
        return genericMemberVariable;
    }

    public T genericProperty { get; set; }
}

As you can see in the above code, MyGenericClass is defined with <T>. <> indicates that MyGenericClass is generic and the underlying type would be defined later, for now consider it as T. You can take any character or word instead of T.

Now, the compiler assigns the type based on the type passed by the caller when instantiating a class. For example, the following code uses the int data type:

Example: Instantiate Generic Class
MyGenericClass<int> intGenericClass = new MyGenericClass<int>(10);

int val = intGenericClass.genericMethod(200);
Output:
Parameter type: int, value: 200
Return type: int, value: 10

The following figure illustrates how the compiler will replace T with int in MyGenericClass.

C# Generic Class

The above MyGenericClass<int> class would be compiled, as shown below.

Example: Compiled Generic class
class MyGenericClass
{
    private int genericMemberVariable;

    public MyGenericClass(int value)
    {
        genericMemberVariable = value;
    }

    public int genericMethod(int genericParameter)
    {
        Console.WriteLine("Parameter type: {0}, value: {1}", typeof(int).ToString(), genericParameter);
        Console.WriteLine("Return type: {0}, value: {1}", typeof(int).ToString(), genericMemberVariable);

        return genericMemberVariable;
    }

    public int genericProperty { get; set; }
}

You can use any type while instantiating a MyGenricClass. For example, the following example uses a string type.

Example: Generic class
MyGenericClass<string> strGenericClass = new MyGenericClass<string>("Hello Generic World");

strGenericClass.genericProperty = "This is a generic property example.";
string result = strGenericClass.genericMethod("Generic Parameter");
Output:
Parameter type: string, value: Generic Parameter
Return type: string, value: Hello Generic World

Generic Class as Base Class

When deriving from a generic base class, you must provide a type argument instead of the base-class's generic type parameter as shown below.

Example: Generic
class MyDerivedClass : MyGenericClass<string>
{ 
    //implementation
}

If you want the derived class to be generic then no need to specify type for the generic base class.

Example: Generic derived class
class MyDerivedClass<U> : MyGenericClass<U>
{ 
    //implementation
}

If the generic base class has constraints, the derived class must use the same constraints.

Example: Constraints
class MyGenericClass<T> where T: class 
{
    // Implementation 
}

class MyDerivedClass<U> : MyGenericClass<U> where U: class
{ 
    //implementation
}

The followings can be generic in C#:

  • Interface
  • Abstract class
  • Class
  • Method
  • Static method
  • Property
  • Event
  • Delegates
  • Operator

Advantages of Generics

  1. Increases the reusability of the code.
  2. Generic are type safe. You get compile time errors if you try to use a different type of data than the one specified in the definition.
  3. Generic has a performance advantage because it removes the possibilities of boxing and unboxing.
Points to Remember :
  1. Generics denotes with angel bracket <>.
  2. Compiler applys specified type for generics at compile time.
  3. Generics can be applied to interface, abstrct class, method, static method, property, event, delegate and operator.
  4. Generics performs faster by not doing boxing & unboxing.