Generics In C# – Its Usage And How It Differs From C++ Templates And Java Generics

Generics allow a type or method to operate on objects of various types while providing compile-time type safety. It can be used to achieve parametric polymorphism – a way to make a language more expressive, while still maintaining full static type-safety. Through Generics, you can generically define a member/method in a class that is valid for all the related types, or you can pass any data type to a function whose parameter has any template. Templates are commonly considered as a compile-time feature. Unlike polymorphism, through interfaces (and inheritance), there is virtually no overhead (more on that later) in using templates, because they are normally turned into equivalent source code during compilation.
In this detailed tutorial, I will tell you how you can implement them, the benefits of this programming model and its difference to Java and C#. Let’s start the journey!

How To Implement Generics?

In my previous tutorial on operator-overloading, I gave you the example of “Vector3f”. Let us continue from where we left. Suppose we want a class for holding three-point vector values (x, y and z), that is generic and accepts any data type including integer, float and double. In order to do that, we need to create different classes for different data types. Fortunately, through generics feature, we can define only a single class with generic semantics that implements the same methods for all the data types as long as the operation on them makes sense. Let’s call our generic vector class as “Vector3“. We can define such class as follows:

The formula to declare our generic class is as follows:

Having that in mind, we can use our class in the program as follows:

As you can see, we can easily create an object of “Vector3“ of any data type that we want. This greatly reduces the need to create separate classes for different types.The above example is for generic class. Note, however, is that you can not use operators on generic data type, because at a time of compilation, a compiler doesn’t know whether those operations make sense. That is a limitation of generics in C# (which I will explain later). However, you can nevertheless overload operators in a class if you are sure that a programmer will use only those types that make sense.

Generic Method

Consider a simple method for printing what a programmer passed to a method to console. Now, for printing different data types (int, float, string etc.) you need to define different methods of the same name (function overloading).

You can see that the implementation is same for all the methods, but as C# is strongly-typed language, you can’t pass double in the parameter for “int”, so we had to define different methods. Fortunately, through generics, you need to only define a single method.

Generic Interface

An interface can be generic too. Consider the following example:

How Generics Work?

As I previously mentioned, Generics is the compile-time feature – meaning it works during compilation of a program. It transforms the class, interface, function etc. that has generic type, into equivalent source code with different class, interface, function etc. of data types that is used when creating an object.

During initialization of an object, compiler will transforms above class into equivalent classes. This will be transformed into the following:

However, note that in C#,  the types are substituted during compilation, so there may be a slight overhead.

Difference to Java Generics

In Java, there is a concept of generics too, which, although looks similar in look, have quite different implementation. Generics in Java provide compile-time safety for type-correctness, but is partially considered as a run-time feature and it is somewhat similar to inheritance-polymorphism in practice. In Java, there is a process called type erasure, through which, type information is removed during compilation and there is no way to tell what was the type of a generic when it was instantiated during run-time. This is considered as a restriction and many programmers are dissatisfied with it. So, any algorithm that requires to know the original type cannot be implemented through generics in Java. You can’t do things like:

Because there is no way to tell during run-time what was the type of “T”. As I said earlier, Java has type erasure, it actually has run-time cost because behind the scene Java’s compiler actually casts the type, something like the following:

See this for more information.

Difference to C++ Templates

In C++, templates are a pure compile-time feature, due to which it greatly increases the compilation speed. The resulting program is bigger in size as well due to the boilerplate code templates in C++ create during compilation. Templates in C++ are more powerful than C# and Java, but are very complex too. It gives a terrible compilation speed during source code transformation. Both provide support for parameterized types. C++ provide substitutions of types during compile time. In C#, however, substitutions are performed at runtime.

In C#, you can not call arithmetic operators on generic type, though you can call user defined operators. In C++, the following code is valid:

C# neither support explicit specialization nor partial specialization which makes Generics not useful in some cases. See this for more information.

Conclusion

Generics is the most useful feature, especially in libraries. Its usefulness can not be dismissed when creating a library for other programmers, considering the fact that is implemented in collections in C#. I find it easy to achieve polymorphism through generics than through the interface

If you have any question, then please ask in the comments section below!

CategoriesC#

Leave a Reply

Your email address will not be published. Required fields are marked *