Monday, June 23, 2008

Hope that your system has loaded with Microsoft's new Visual Studio 2008. I was really excited when I saw the new features of C# 3.0. In this article, I am going to brief you about the new features of C# 2.0 and 3. The reason I have taken C#2.0 also is for "Generics".
If your company yet to buy VS2008, don't worry. You can download FREE express edition of VS2008 at http://www.microsoft.com/Express/Download/.

Let us start.

When I have a chance to see Ruby code a year before, I was really astonished by its clean syntax of. Three main aspects that are impressed me lot. These are:
1. Clean syntax
2. Simple syntax
3. Smart syntax

After a long while, I saw the new features of C# 3.0 those are just inspired by Ruby's syntax and features. After gone through the small exercise on various new features, I just really love C# 3. Before looking into these, it could be helpful to know about Generics, a feature derived from C++.

Generics
If you are coming from C++ (learned in academic also a worth), you know the "Templates". It provides a kind of reusability. When you need to store a collection of objects, the first choice was ArrayList in the days of .NET 1.x. It lets you store a collection of any type. When you iterate through the collection, you should very careful about type casting of the object in the collection. To store a collection of objects with same type, then Plain Old Array (please do not try to create another TLA - Three Letter Acronym POA) is the best choice. Then what is the necessary for Generics.

The first concern with .NET 1.x collection types is the type casting a.k.a boxing/unboxing. These collections only knows "System.Object". Each time when storing or retrieving, we have to pay the cost of boxing/unboxing.

The second concern is the need of strongly-typed collection. Suppose you want to store a collection of object of type "Account", you have two choices based on the usage frequency of "Account" collection. Either you have to create custom collection by deriving IEnumerable. Otherwise, the illiterate "ArrayList".

The above two are the main reasons for the born of C# Generics inspired by its grand father "C++" in its version 2.0.

Assume that whenever you need to implement common behavior for more than one type, you can just put a place holder on the type declaration. Suppose, I want to implement common behavior for object storage with "Stack" model, in .NET 1.x period, I have to declare it as:


public class Stack
{
private int _position;
private object[] _elements = null;

public void Push(object element)
{
if(_position <= _elements.Length) _elements[_position++] = element; // else through exception } public object Pop() { if(_position >= 0) return _elements[_position];
}
}


In the modern age of .NET 2.0, I can put a place holder for type declaration like:


public class MyStack<T>
{
private int _position;
private T[] _elements = null;

public MyStack(int capacity)
{
_elements = new T[capacity];
_position = 0;
}

public void Push(T element)
{
if (_position < _position =" _elements.Length">= 0) return _elements[_position--];
return default(T);
}
}

In line 1, I have declared MyStack class with the place holder T. You can use any name within the angle bracket (< >). But you should use the same name across the code. After specified the place holder, I have assumed and used T as a strong type.

In line 15, you can see that the Pop() method returns either the element at the head of "null" value of the type. How can you specify the null value of a type. Here, the problem is I have to return "null" for reference type and default value for value types. For this, C# provides "default" keyword which returns default value of the given type. Ok, now how can you use this class for all variety of types:


MyStack<int> s = new MyStack<int>(2);
try
{
s.Push(100);
s.Push(200);
s.Push(300);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

Console.WriteLine("1: {0}", s.Pop());
Console.WriteLine("2: {0}", s.Pop());
Console.WriteLine("3: {0}", s.Pop());

You can see the output like this:

Stack full
1: 200
2: 100
3: 0

Here, when I tried to get the top element third time, it returns default value of "int" type 0.

You can declare Generic on struct and interface also. .NET 2.0 provides the following interfaces:
  • ICollection
  • IComparer
  • IDictionary
  • IEnumerable
  • IEnumerator
  • IList
And, it provides generic based collections under the namespace System.Collection.Generics.

Generic Method
You can also use/apply Generic in a method which might be a static or non-static member of either generic and non-generic type. Like the declaration of Generic type declaration, you specify the template like the following:
public void MyGenericMethod<T>(T arg1);


Generic methods change the way we use factory methods. For example, in .NET 1.x, we declared factory method like the following:

public object CreateInstance(Type t);


If you need to use this method, you have to use boxing/unboxing, like:

Account myAccount = (Account) MyClass.CreateInstance(typeof(Account));


But, when you use Generic on this method like
public T CreateInstance<T>();


You can simply use CreateInstance like:
Account myAccount = MyClass.CreateInstance<Account>()


See the clear syntax of the Generic method. And it is not necessary to apply type casting also.

Obviously you can use Generics in delegates also.
-to be continued.

0 comments: