Skip to main content

The evolution of C# Part II - Generics

This is a well discussed matter throughout the internet. Everyone knows about generics, what they do and what they are used for, right? No. There is a variety of reasons why you wouldn't know about generics, and some of them are:

  • You are new in the language
  • You are not new in the language but never cared to learn it
Simply because you never learned the basics about generics, it doesn't mean you've never used it. If you recognize this snippet, then you are already dealing with generics:


So, what is the advantage of generics?

Type safety
Generics will allow you to catch the errors at compile time rather than runtime by enforcing the rules of type safety that make C# a statically typed language. This leads to increased productivity because you don't have to run the code to know that something is wrong. For example, if in the snippet above you tried to add a new item of type string, a compiler exception would be thrown.

Typically, in C# 1.0, you would use an ArrayList collection to contain a collection of items, independently of the type. I think i never needed more than one type in the same collection, but ArrayList lets you create a mixture of different types. By providing the type you want the List to contain, the compiler will generate it for you behind the scenes and will recognize that in that instance you will only have int's.  Example:


The same would happen for Add, Remove and all the other generic methods of the List class. More on that later.

Performance
Performance is one of the main advantages of using generics in the situation described above. When you add an item to an ArrayList, you are performing a boxing operation (which means you are creating a special object and putting your value inside it), and when you retrieve it you need to downcast it to your type, performing and unboxing operation. This boxing/unboxing can become heavy when you do it multiple times like traversing a big collection.

By telling the collection which type it is dealing with you avoid that inconvenience of having to downcast your type from object in order to use it, and that will lead to better performance. Of course, the difference is only visible when you're dealing with big collections, but it is there.

Code Reuse
I think that this is the biggest advantage of having generics in your toolbox. When dealing with collections of items in C# 1.0, if you wanted to have the above benefits you would need to create your own collection. Imagine the overhead of manually creating a PersonCollection, BoatCollection, CarCollection, etc. Instead, we can now use generics for this daunting task! List(of T) does exactly that, so let's look at it's declaration:

The only unusual thing here is the T that comes after the name of the class. That is what allows us to pass the type that we are dealing with and is called a type parameter. Inside your generic class, you use T (or whatever name you give it) to refer to the type that the client code passes. When you create a List(of T), the compiler will create a class the way you would manually do. This means that you can reuse that code a lot more.

Let's explore the capability of Generics by creating a collection of our own:

As we can see, this is not a difficult concept to grasp. We create a new class called MyCollection which receives a type parameter. To this type parameter we will refer as T inside our class. We can see that we have a property called LastItem of type T which represents the last item added to our collection. We have also a method that receives a T and returns it after adding it to our internal collection and firing an ItemAdded event. Note that this event itself uses the type argument and a generic delegate meaning that it's second argument will be of T.

One thing to note in our implementation is that we are using generic constraints. These are the where T : Person that we see up there in the declaration. When we use constraints, the client will only be able to pass in a type that implements, or inherits, from those constraints. If Person is a class, then we will only be able to pass Person or a more derived type. Also, inside our generic class, we have access to the members in the Person type, because we know for a certainty that we are dealing with a Person. We can specify as a generic constraint the following:

  • a type
  • an interface
  • the special keywords class and struct
  • another type parameter 
  • new() This will let you specify that the type must have a public parameterless constructor.

This is how you would use the MyCollection class in a typical case:

We can see here that we used this collection combined with the Person type. After we specified the type, the compiler has all the information to create the class and analyze all the calls. The event handler is fired with the second argument of type Person, as we specified in the event declaration. The method AddAndReturnTheSame will receive and return a Person.

We can also have a generic method in a non-generic class, like so:


Note here that we are specifying the type parameter when we declare the method. There is no need to include this type when calling the method, because the compiler can do that for us inferring by the type of the parameter we are passing. This makes it simple for us to call the method without specifying the type parameters. We have the option specify constraints in this types too, if we may need.

What to use it for
A new namespace (System.Collections.Generic) has been created on C# 2.0 specially for containing the generic collections. List(of T) is one of the most used, but we also have a Dictionary(of TKey, of TValue) that you can use in almost the same way as you use an Hashtable (but with the above benefits) and also the whole base structure that supports this and other generic collections.

The whole concept of generics is more applied to collections in general, but that's not a rule. You can use it obviously wherever you want, including classes, interfaces, methods or even delegates. Using generics will provide more flexibility to your code, but can also reduce it's readability if you use it too much. Still, there are situations where i have applied it very successfully. The example i'm referring to was a user control that when clicked created a pop-up form. Using generics allowed me to reuse the code only by specifying some constraints. This way the User Control would never know the type of the Form, but could instantiate it anyway.

The default keyword
The default keyword has a very specific meaning in generic code. It takes a parameter which is the name of a type and it returns the default value of that type. So, if you pass it the name of a class it will return null, if you pass it a struct it will return a struct with all the fields initialized to the default value and so on. See the snippet:


Take a good look at this C# 2.0 feature and have fun coding!

Thanks.

Comments

Popular posts from this blog

The repository's repository

Ever since I started delving into architecture,  and specifically service oriented architecture, there has been one matter where opinions get divided. Let me state the problem first, and then take a look at both sides of the barricade. Given that your service layer needs to access persistent storage, how do you model that layer? It is almost common knowledge what to do here: use the Repository design pattern. So we look at the pattern and decide that it seems simple enough! Let's implement the shit out of it! Now, let's say that you will use an ORM - here comes trouble. Specifically we're using EF, but we could be talking about NHibernate or really any other. The real divisive theme is this question: should you be using the repository pattern at all when you use an ORM? I'll flat out say it: I don't think you should... except with good reason. So, sharpen your swords, pray to your gods and come with me to fight this war... or maybe stay in the couch? ...

Follow up: improving the Result type from feedback

This post is a follow up on the previous post. It presents an approach on how to return values from a method. I got some great feedback both good and bad from other people, and with that I will present now the updated code taking that feedback into account. Here is the original: And the modified version: Following is some of the most important feedback which led to this. Make it an immutable struct This was a useful one. I can't say that I have ever found a problem with having the Result type as a class, but that is just a matter of scale. The point of this is that now we avoid allocating memory in high usage scenarios. This was a problem of scale, easily solvable. Return a tuple instead of using a dedicated Result type The initial implementation comes from a long time ago, when C# did not have (good) support for tuples and deconstruction wasn't heard of. You would have to deal with the Tuple type, which was a bit of a hassle. I feel it would complicate the ...

C# 2.0 - Partial Types

For those of you interested, i found a very interesting list of features that were introduced in C# in  here . This is a very complete list that contains all the features, and i'm explaining them one by one in this post series. We've talked about  Generics  and  Iterators . Now it's time for some partial types . A partial type  is a type which definition is spread across one or more files. It doesn't have to be in multiple separated files, but can be. This is a very simple concept that can give us many benefits, let's see: If a type is partial, multiple developers can work on every part of it. This allows a more organized way of working and can lead to production improvement.  Winforms , for example, generates a partial class for the form so that the client can separately edit other parts it. This way, a part contains information about the design and the other contains the logic of the form. In fact, this is a very spread pattern across .Net. Ent...