Saturday, December 12, 2009

C# 2.0 - Generics


Hi all,


.NET 2.0 team came up the new concept of Generics. Its a really cool feature for C#.
 But what is generics by the way????


To really understand Generics, we have to consider the need to create a class that will manage a collections of objects. The objects can may be any type compile time by a parameter passed to the class. Moreover, the collection class must be type-safe.


In 1.1 version of C#, there is no way to create such a class. Therefore, the only option for us earlier is to use cast
In short, Generics are parametrized types. 


Lets focus on C# 1.0 semantics:


C# 1.0



If we want to implement a stack data structure using system collections, the code would look this:


-----------------------------------------
using System.Collections;


Stack s = new Stack();
s.Push(4);
int = (int) s.Pop(); // Cast is a MUST
-----------------------------------------


Since Stack is an object and if want get a value from the stack, we have to CAST as an integer value.


C# 2.0 


If we use C# 2.0 sematics, we can use power of Generics. The following code willl follow:


----------------------------------------
using System.Collections.Generics;


Stack s = new Stack();
s.Push(4);
int i = s.Pop(); // No cast needed.
-----------------------------------------


It has a better semantics and more clear. Generics supports any managed language can take advantage of.
Generics has 2 benefits:


1) Type Safety:


Now consider this scenario (C# 1.1)


---------------------------------------------
using System.Collections;


Stack s = new Stack();
s.Push(4); 
s.Push("five"); // ????



object o =  s.Pop();
//now what??? 
---------------------------------------------


When we pop from stack, what type object it would be?? It means we have maintain an ugly switch statements. It looks ugly.


With C# 2.0, if we try to use same code:


------------------------------------
using System.Collections.Generics;


Stack s = new Stack();
s.Push(4);
s.Push("five"); // compile time error!
-------------------------------------


Compile time errors are the best because we can not run this code before fixing it.


2) Performance.


Value types (int, float, struct etc) need require boxing and unboxing if we treat them as objects. This means that boxing value types into an object and unbox object to the value types. 


Therefore, if we use C# 1.1,
--------------------------------
Stack s = new Stack();
s.Push(4); // BOXING happens. Push method expects an object. When we are putting 4 in the stack, IL boxes the value type into an object.


int i = (int) s.Pop(); // Unboxing happens. Unboxes convert obect into value type (by casting)
------------------------------
It means, IL has to do extra work.


In contrast, C# 2.0, we can circumvent the heavy operations such as boxing/unboxing and  use Generics:
------------------------------------
Stack s = new Stack();
s.Push(4); // No Boxing here


int i = s.Pop(); // No Unboxing here.
------------------------------------


Why we call boxing/unboxing heavy operations??
The reason is boxing increases pressure on the managed heap. This result call garbage collection more often.
Similarly, if we do not use value types and we are reference type, then we have to casting is required Either way, some kind of heavy operations have to be performed. 

We dont have to worry about this if we are using Generics. Because its strongly typed all the way through. 

A very common Generics usage: 


class Pair 
{
   public S First {get;set;}
   public T Second {get;set;}

   public Pair(S first, T second)
   {
     First = first; Second = second;

   }

}


Pair Foo()
{
  return new Pair(true, 17); 

}



Cheers, 
--aaroh




Reference: 
Channel9 C#

No comments:

Low Code Reimagined with AI + Copilot Pitch Deck - Copy Copilot day (Virtual) - 2023

 Hi All,  I presneded a session at Pune UG on Low Code Reimagined with AI + Copilot Pitch Deck.  Video is at this address  https://www.youtu...