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:
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:
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.
- 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
Post a Comment