Site icon

Generics in C#

Generics in C# allows you to write type safe, reusable and high-performance code, it is a very handy feature and was introduced in C# 2.0. In this article, we will learn about the basic concept of generics, its benefits and the usage. 

What is generics in C# ? 

Generics is a language feature, which allows us to design classes, methods, Interface and delegates without any specific data type. The data type information is passed to the generic type during declaration and instantiation time.

This enables in developing common classes, methods, Interface and delegates, which helps in the application performance, improves the productivity and provides the type safety feature.

This is what Microsoft says about generics.

 “Generics are the most powerful feature of C# 2.0. Generics allow you to define type-safe data structures, without committing to actual data types. This results in a significant performance boost and higher quality code, because you get to reuse data processing algorithms without duplicating type-specific code”

Generic method in C#:

A generic method with a type parameter specification <T>  declared as follows:

public void MyGenericMethod<T>(T value)
{
   Console.WriteLine(value.ToString());
}

In above, we have declared a Generic method. Here, <T>  stands for the type parameter, that will be provided during the method invocation time. Lets take below example as follows.

Example 1: Generic method in C#
class Program
{
   static void Main(string[] args)
   {
       //Generic method call by passing string parameter
       MyGenericMethod<string>("Hello world");
       //Generic method call by passing int parameter
       MyGenericMethod<int>(12345);
       Console.Read();
   }
   //Generic method declared with T as parameter passed.
   public static void MyGenericMethod<T>(T value)
   {
       Console.WriteLine(value.ToString());
   }        
}

This generates below output.

Generic method example

Here in above,

So here the compiler does a type check and allows only the specified types and throws error if it finds any other type. This is what we say as type safety property of generics.

Generic Class in C#:

A classic example of an inbuilt generic class is a List<T>, <T> is the data type. It allows you to create lists of various data types without sacrificing type safety. 

List<int> intList = new List<int>();
List<string> strList = new List<string>();

Create a Custom Generic class in C#:

A generic class with a Type parameter specification <T>  declared as follows.

public class MyGenericClass<T>
{
    public void MySimpleMethod(T value)
    {
         Console.WriteLine(value.ToString());
    }
}

In the above code sample.

Example 2: Generic Class in C#

Lets take an example as follows.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Output from generic class:");
        MyGenericClass<String> myClassObj = new MyGenericClass<String>();
        myClassObj.MySimpleMethod("Hello world");

        MyGenericClass<int> myClassObj2 = new MyGenericClass<int>();
        myClassObj2.MySimpleMethod(12345);
        Console.Read();
    }
}
public class MyGenericClass<T>
{
    public void MySimpleMethod(T value)
    {
        Console.WriteLine(value.ToString());
    }
}
Generics class example output

Herein above,

Benefits Of Generics in C#:

Following are the benefits that Generics brings to our program.

How Generics are type safe ? 

Type safe means that the compiler performs a check on the types during compilation and throws error when it finds an incompatible data type.

In C#,   ArrayList class is not type-safe because it allows to store any object.  For instance, If you look at below code example, It will compile without any error or warning. However during run-time, it will throw InvalidCastException.

ArrayList arrlstNumber = new ArrayList();
arrlstNumber.Add(10);
arrlstNumber.Add(1.5);
arrlstNumber.Add("Hello world");
int sum = 0;
for (int x = 0; arrlstNumber.Count; x++)
{
int value = (int)arrlstNumber[x];
sum = sum + value;
}

Above code will compile fine because. ArrayList.Add(Object obj) method allows objects .

In C#, all types are derived from System.Object. So we are able to add an integer (10),  a float (1.5) and a string (“Hello world”) to the ArrayList arrlstNumber without any compile time error.

When we run the above program.

Generics  will be useful in this scenarios in-order to remove run-time errors and to ensure that errors are caught at compile time.

Lets check how Generics solves this issue ?

While using Generics, the compiler understands and determines the type and ensures that objects compatible with that specific type is used in the generic method or generic class. It throws compile time error when  it finds an incompatible type.

Lets use a Generic type List<int> to the above example.

List<int> arrlstNumber = new List<int>();
arrlstNumber.Add(10);
arrlstNumber.Add(1.5);//Compile error
arrlstNumber.Add("Hello world");//Compile error
int sum = 0;
for (int x = 0; x < arrlstNumber.Count; x++)
{
sum = sum + arrlstNumber[x];
}

As soon as the compiler sees the type <int> then it ensures that there will be only int variables in the List<int> arrlstNumber. So there is compile time type check which ensures any possible run time issue.

How generics provides code re-usability?

Generics allows us to design type independent function, class, interfaces, delegates, events etc. that can be reused across different types. Lets check below sample example on swapping of two number.

The above example runs fine for integer type variable only. If we try to swap two string variable, then the compiler throws a compile time error as shown below.

In below example, the generic method SwapNumbersGeneric(ref T num1, ref T num2)  is called by string, integer and decimal types.
static void SwapNumbersGeneric<T>(ref T num1, ref T num2)
{
    T tempNum = default(T);
    tempNum = num1;
    num1 = num2;
    num2 = tempNum;
}

Having a Generic method to swap two values removes the possibility of creating separate methods for each type.  Look at below code example.

using System;
namespace GenericSwappingExample
{
    class Program
    {
        static void Main(string[] args)
        {
            string x = "100";
            string y = "50";
            Console.WriteLine("Before swapping string – x : {0} , y : {1}", x, y);
            SwapNumbersGeneric(ref x, ref y);
            Console.WriteLine("After swapping – x : {0} , y : {1}", x, y); int n1 = 1000;
            int n2 = 150;
            Console.WriteLine("Before swapping Integer – n1 : {0} , n2 : {1}", n1, n2);
            SwapNumbersGeneric(ref n1, ref n2);
            Console.WriteLine("fter swapping – n1 : {0} , 2 : {1}", n1,n2);decimal d1 = 10.125M;
            decimal d2 = 00.125M;
            Console.WriteLine("Before swapping decimal – d1 : {0} , d2 : {1}", d1, d2);
            SwapNumbersGeneric(ref d1, ref d2);
            Console.WriteLine("After swapping – d1 : {0} , d2 : {1}", d1, d2);Console.Read();
        }
        static void SwapNumbersGeneric<T>(ref T num1, ref T num2)
        {
            T tempNum = default(T);
            tempNum = num1;
            num1 = num2;
            num2 = tempNum;
        }
    }
}

Output –

Continuing on this, In the next article, We explore at the performance benefits that Generics provides in a program comparatively to non Generic type. Click here to check it out.

Exit mobile version