Generics in C# is a very handy feature, it was introduced in C# 2.0. It allows you to write which allows to write type safe, reusable and high performance code.

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 mechanism in C#, 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”

Create a Generic method in C# :

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

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.

Generic method

Here in above, we are invoking the Generic method MyGenericMethod<T>(T value) from the main method by specifying  string type and then integer type. 

If we declare something like this – MyGenericMethod<string>(12345); we will get a compile time error, because we have specified string type but passing an integer parameter. However, this MyGenericMethod<int>(12345); will work fine. 

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.

Create a Generic class in C# :

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

In the above code sample, we have declared a Generic class. Here, <T> stands for the type parameter, the Generic class type can be explicitly specified during the class instantiation.

Here, we haven’t specified the <T>  before the method declaration. Its optional in this case,  the same Generic class type parameter can be reused.

We can also declare as  MySimpleMethod<T> in side the generic class without any error.

We can invoke above Generic class by specifying different data types. Lets take an example as follows.

Figure 2 - generic class output

Herein above, we declared MyGenericClass  of  <string>  type and pass the string as method parameter.

Again from the Main method, we have declared MyGenericClass of <int>  type and pass the int parameter.

In both cases the code works fine, since we have instantiated and also provided same type parameter to the Generic class method.

However, we will get compile time error if we do something like this as shown below. Here type mismatch happens and compiler throws compile time error.

Benefits Of Generics :

Following are the benefits that Generics brings to our program.

  • Generics are type safe.
  • Generics provides code re-usability.
  • Generic has a performance advantage over non-generics.

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.

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.

Non generic invalid cast exception example

When we run the above program. It successfully casts the first variable which is of  the type integer (10) from the array list and assigns to the temporary variable. However, it throws InvalidCastException while casting the second variable (1.5) which is of type float to integer.

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.

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.

Generic type safe example

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.

non generic swapping number example

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.

Non generic swapping value

In below example, the generic method SwapNumbersGeneric(ref T num1, ref T num2)  is called by string, integer and decimal types.

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

Output –

generic swapping number

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.