What is Generics in C#?

Generics was introduced in C# 2.0 ("System.Collections.Generic" namespace) and it is a most powerful feature. It allows us to create classes and methods with placeholders as a type parameter (which are type-safe). It helps to reuse data processing algorithms without replicating type-specific code. In C#, the compiler will replace a placeholder with the specified type at compile time.
Generic types perform better than normal system types because they reduce the need for boxing, unboxing, and typecasting the variables or objects.

Why Use Generics?

Suppose you are writing a class for Calculator with methods Add() and Subtract(). You have to implement this class in such a way that it works for any data type. Now you will have two options if generic was not there to help you.
Option 1 - Define classes for each data types
For each data type, we need to create a class to achieve the goal. However, there are many disadvantages of this approach,
Option 2 - Defined class for data type as an object
This is somehow better than the first approach. However, it has its own disadvantages.

Our Hero - Generic solves all the above problems

Q. Need to know how generic type is constructed?
A. During compilation time, when generic types or generic methods are converted to MSIL (Microsoft Intermediate Language) that time it contains metadata where generic type parameters are defined. The actual construction process of generics type is based on parameter constraint either Value type or Reference type. Value type and Reference type generic type construction are different.

Where we can apply generics in C#

Generic Collection

The following will show some generic collection list which is in .NET framework.

Generic Constraints

Constraints are validations that we can put on the Generics Type parameter. At the instantiation time of generic class, if the client provides an invalid type parameter, then the compiler will give an error.
Constraint Description
where T: class The type must be a reference type.
where T: struct The type must be a value type.
where T: new() The type must have a public parameterless constructor.
where T: <base class name> The type must be or derive from the specified base class
where T: <interface name> The type must be or implement the specified interface.
where T: U Type supplied for T must be or derive from the argument supplied for U.
Learn more
Here is a detailed tutorial with code examples on generics: Using Generics in C#