Generics and Constraints over Generics

In this post,  I am going to discuss about Generic Classes and bit more on this.  Just for a smooth start,

“Generics were introduced in .NET 2.0, which provides us a way to create Classes/Methods/Types and many more without specifing the specific type of parameters. Parameters must be provided at the time of creating the instances. So we can say Generics are only a blueprint/templated version and actual type is defined at Runtime.”

So lets first create a simple Class say Point

public class Point<T>
    {
    }

Here as you can see, I have created a generic class Point, its coordinates X and Y can be of any type.

So in this post, I am going to mainly discuss, Constraint with generics.

Its very imperative to have a Generic Class, which can accept any type of parameter. But sometimes one might require that your generic Class can be instantiated with only specific types. Like say you want that a Generic can be instantiated with only say a Class Point Type or of its derived types.  Is it possible ?

Yes this is possible.

And also, C# provides a very robust way to implement this feature. So using it, It can be very helpful at certain times to define a constraint over Generic.

So what are the ways to do this. We’ll first take few examples then. Later we will conclude .

So First, How can we define constraint with Generics. It is done using where clause.

We have two types of variable in C#. reference and Value..

No.. …

Now we have three types:

  • Reference
  • Value
  • Nullable ( It is having feature of both types)
So we’ll discuss about Nullable type in some other post. Let’s stick to to constarint in Generic type. So what will you do if you want to have Generic type that can be instantiated as Value type. Do we need to make a comma separated list of all the possible value types.
NO..
We know, In C#, A Class is a reference type and Struct is a value type. So we can define a generic that will be instantiated of Value type only. Like here my Point class could be one real time example that can be instantiated to a Value Type. It can be done as
public class Point
          where T1 : struct
    {
       ...
    }
Similarly,  If we want a generic that can be of  Reference type only, that can be as just opposite to above one.
Public Class Queue: where T:Class
{
}
You also can have multiple restriction. You can put a comma separated list. So how can you do this. It can be like
public class Point
          where T1 : class
    {
       ...
    }
But what is meant Whether T would follow all or anyone of them. It should follow all, like here T must implement all three interfaces  IEnumerable, IList, IDisposable.
There are few restriction on this. While providing multiple restriction, it can contain only one class but it can have multiple interfaces. Also there are some restrictions on ordering of the types. The class or struct key word should come first and if Class/Struct is there it requiries to be written ahead of All. And after this any class or base class then all other Interfaces.
We can also have multiple restriction on a Generic Type but it should not be conflicting. Like we can never say
Public class Point where T: struct, class
    {
       ...
    }
It’ll be a compile time error.
So One more constraint we can have like
Public class Point where T: new()
    {
       ...
    }
So what it means here, It means T must be a type that have a parameter less constructor. I can have parameterized but it also must have parameter less one also. It can also also be accompanied with other restriction also but this should be last in the list.
Similarly, you can apply contstraint on those Generic Types that have multiple parameters. Like my below one
public class Point
          where T1 : class, new()
          where T2 : IList
    {
       ...
    }
Here also you have option to apply the constraint to any one of  them or both of them or some of them.
I think that’s all about Generic constarint.
One thing you might wonder, whether the following is possible
public class Point
          where T1 : int
    {
       ...
    }

But this is not possible. The constraint must be an interface, a non-sealed class or a type.

When you will compile will get an ERROR “A type used as a constraint must be an interface, a non-sealed class or a type”.

I was thinking to have this one also, but not there. But you might except it in the coming version of C#.

Hope you all must have liked this. Do share your feedback

Cheers,

Brij

One thought on “Generics and Constraints over Generics

Leave a comment