Showing posts with label Generics. Show all posts
Showing posts with label Generics. Show all posts

Sunday, August 8, 2010

What are Generics?

Hello Friends,

Generics are part of the .NET Framework's type system that allows you to define a type while leaving some details unspecified. Instead of specifying the types of parameters or member classes, you can allow code that uses your type to specify it. This allows consumer code to tailor your type to its own specific needs.

The .NET Framework version 2.0 includes several generic classes in the System.Collections.Generic namespace, including Dictionary, Queue, SortedDictionary, and SortedList. These classes work similarly to their nongeneric counterparts in System.Collections, but they offer improved performance and type safety.


Why Use Generics?
Versions 1.0 and 1.1 of the .NET Framework did not support generics. Instead, developers used the Object class for parameters and members and would cast other classes to and from the Object class. Generics offer two significant advantages over using the Object class:

Reduced run-time errors:
The compiler cannot detect type errors when you cast to and from the Object class. For example, if you cast a string to an Object class and then attempt to cast that Object to an integer, the compiler will not catch the error. Instead, the runtime will throw an exception. Using generics allows the compiler to catch this type of bug before your program runs. Additionally, you can specify constraints to limit the classes used in a generic, enabling the compiler to detect an incompatible type.

Improved performance
Casting requires boxing and which steals processor time and slows performance. Using generics doesn't require casting or boxing, which improves run-time performance.

How to Create a Generic Type
First, examine the following classes. Classes Obj and Gen perform exactly the same tasks, but Obj uses the Object class to enable any type to be passed, while Gen uses generics:

// C#
class Obj
{
public Object t;
public Object u;

public Obj(Object _t, Object _u)
{
t = _t;
u = _u;
}
}

class Gen
{
public T t;
public U u;

public Gen(T _t, U _u)
{
t = _t;
u = _u;
}
}

As you can see, the Obj class has two members of type Object. The Gen class has two members of type T and U. The consuming code will determine the types for T and U. Depending on how the consuming code uses the Gen class, T and U could be a string, an int, a custom class, or any combination thereof.

There is a significant limitation to creating a generic class: generic code is valid only if it will compile for every possible constructed instance of the generic, whether an Int, a string, or any other class. Essentially, you are limited to the capabilities of the base Object class when writing generic code. Therefore, you could call the ToString or GetHashCode method within your class, but you could not use the + or > operator. These same restrictions do not apply to the consuming code because the consuming code has declared a type for the generic.

How to Use Constraints
Generics would be extremely limited if you could only write code that would compile for any class, because you would be limited to the capabilities of the base Object class. To overcome this limitation, use constraints to place requirements on the types that consuming code can substitute for your generic.

Generics support four types of constraints:

Interface Allow only types that implement specific interfaces to use your generic.

Base class Allow only types that match or inherit from a specific base class to use your generic.

Constructor Require types that use your generic to implement a parameterless constructor.

Reference or value type Require types that use your generic to be either a reference or value type.

Use the As clause in Visual Basic or the where clause in C# to apply a constraint to a generic. For example, the following generic class could be used only by types that implement the IComparable interface:


// C#
class CompGen where T : IComparable
{
public T t1;
public T t2;


public CompGen(T _t1, T _t2)
{
t1 = _t1;
t2 = _t2;
}

public T Max()
{
if (t2.CompareTo(t1) < 0)
return t1;
else
return t2;
}
}

The preceding class will compile correctly. However, if you remove the where clause, the compiler will return an error indicating that generic type T does not contain a definition for CompareTo. By constraining the generic to classes that implement IComparable, you guarantee that the CompareTo method will always be available.

Thanks,
Paras Sanghani