Constraints are like rules or instructions to define how to interact with a generic class or method. They can restrict the parameter that will be replaced with T to some certain type or class or have some properties, like to be new instance of class.
If the consumer of the generic method or class didn’t comply with the constraint set on the parameter T, it will result in a compilation error.
With constraints you can for example, specify a generic parameter to only accept reference types (class), or value types (struct), or to be a class that implements an interface.
Constraints can be defined using the keyword where
Let’s see the below example that includes having a constraint on the above Lesson class, we will put a constraint that the parameter T should only be of a reference type, value types are not allowed. so it will be defined as where T: class
Now if you try to intialize the above Lesson class using a non-reference type as its parameter, like int , you will get a compilation error:
The type ‘int’ must be a reference type in order to use it as parameter ‘T’ in the generic type or method ‘Lesson’
You can only call it with a reference type, like string or any class.
You can define constraint that a parameter must be implementing some interface. Let’s take this example:
Here you have a class Container, that defines a generic parameter T, with a constraint that anyone wants to use this class, must pass an argument that implements the IItem Interface.
So here we added the IItem Interface, that has a method showName().
We also added a class Item, that will implement IItem Interface.
Now in the caller part, what will happen is that we will initialize Item object, and then initialize Container while providing it and Item Type, and then calling the set method of container to set the item that was initialized.