Getting started with generics
With generics, the CLR offers us another way to ensure code reuse. If you’re a C++ developer, you might be tempted to see generics as some sort of C++ templates. Even though there are certain similarities, the truth is that there are several important differences. For instance, in C++ the source code must be available for the developer instantiating the template. That is not the case with generics in .NET (there are other differences, many captured here). Before going on, I believe it’s a good time to show some code. When generics were introduced, they solved a really bad problem: how to encapsulate an algorithm and make it generic and type safe at the same time. The best way to understand it is to look at a quick example:
In the previous snippet, MyList is a class which works with any data type (notice the <T> right after the class definition). T is called a type parameter and you can see it as a name which can be used anywhere a data type is supposed to be used. Since the type parameter was introduced by the class itself (notice that <T> is declared right after the class’ name), it can be used for fields,method’s parameter and return values. You can even used it as local variables from within the class’ methods. After creating a generic type,you can redistribute it and let other developers reuse it with a concrete type. For instance, here’s how you can reuse the previous class for storing lists of integers:
If you’ve tried to pass a string to intList’s Add method, you’d get a compile error. So, in .NET, generics are type safe because the compiler will always ensure that only objects compatible with the used data type parameter can be used where objects of that type are expected. If you’ve only started using .NET in the last years, then you probably haven’t noticed the performance improvement gained through its introduction. Before generics, generalized algorithms resorted to the Object type. Unfortunately, that meant that using those classes with value types would always result in boxing operations. This was really bad and you’d also need to use lots of casts to access the values or objects saved by those classes. Thank god we’ve got generics!
Currently, the framework introduces several utility classes built with generics. For instance, the System.Collections.Generic, System.Collections.Object and System.Collections.Concurrent namespaces introduce several generic collection classes which should always be used whenever you need to work with collections and lists of elements. And yes, nothing prevents you from creating your own generic types. Currently, you can create generic reference and value types, but you cannot create generic enumerated types. Notice that you can even create generic interfaces, delegate and methods (useful for those cases where only the method encapsulates a reusable algorithm). Creating a generic is an interesting process, but we’ll leave that analysis for the next post. Stay tuned.