An Overview About Generics In C#.NET

History:

The approach of generic programming has been started in 1983 by Ada programming language to reduce the duplication of code by writing a common set of methods and types that differ only by types or environment they are being used.

Introduction:

The term generic programming was originally coined by two guys named David Musser and Alexander Stepanov  to describe an approach for software decomposition. In this approach fundamental requirements on types are abstracted from across concrete examples of algorithms and data structures.

So in general terms generic programming is a style of computer programming in which algorithms are written in terms of to-be-specified-later types that are instantiated when needed for specific types provided as parameters.

Genericity is implemented and supported differently in various programming languages like BETAC++DEiffelAdaEiffelJavaC#,F#, and Visual Basic .NET. Generics were added as part of .NET Framework 2.0 in November 2005, based on a research prototype from Microsoft Research started in 1999. The concept of Templates in C++ is same as that of generics in C#.

Overview of Generics:

Generics are a way to make your methods, classes, interfaces, and delegates work for multiple types while still being type safe. Using what are known as “type parameters,” you can allow your methods to work with a “generic” type that will represent a specific type that will be provided in the calling code. By creating a generic class, you can create a collection that is type-safe at compile-time.

When our code compiled by compiler, it compiles down to IL and metadata just like any normal type. The IL and metadata contains additional information that knows there’s a type parameter. This means you have the type information at compile time.

Then .NET Common Language Runtime(CLR) creates a specialized copy of the native code for each generic type instantiation with a value type, but shares a single copy of the native code for all reference types, since at the native code level, references are just pointers with the same representation.

Example:

Lets take a simple example where we see the magic of generics.

//old way:
ArrayList arrayList = new ArrayList();
arrayList.Add(“Hello World”);
//this does not generate a compiler error:
arrayList.Add(1);
foreach (object obj in arrayList)
{
//this will cause an exception if we’ve added any non-strings     string str = (string)obj;     Console.WriteLine(str);
}
//new way:
List listOfStrings = new List();
listOfStrings.Add(“Hello World”);
//this generates a compiler error:
listOfStrings.Add(1);
foreach (string str in listOfStrings)
{     //no need to cast, since we can take strings directly out of the list     Console.WriteLine(str);
}

Terms Used in Generics

Type Safety:

Before knowing much about generic we must be familiar with the word type safety. So type safety is the extent to which a programming language prevents type errors. A type error is erroneous or undesirable program behavior which is found when a compiler found different type rather than expected type.

Type Parameters:

In a generic type or method definition, a type parameters is a placeholder for a specific type that a client specifies when they instantiate a variable of the generic type. A type parameter is passed to a generic method/class/interface/delegate and used as the generic type. It must be contained in angle brackets <Type>. This comes immediately after the name of the method/class/interface/delegate you are creating

Example:

public void DoSomething<t, u="">(T parameter1, U parameter2){...}

In this example, we used two type parameters, and specified that the first method parameter be of type T, and the second be of type U. Those types must be provided when calling the method.

Generic Methods

First, we’ll create some generic methods. For example’s sake, let’s create a method that takes a List of any type, and converts it to an array of the same type. (Note, this method already exists, but we’ll recreate the wheel for example’s sake). Such a method might look like this:

public static T[] ConvertListToArray(List list) {
    int count = list.Count;
    T[] array = new T[count];
    for (int i = 0; i < count; i++)
        array[i] = list[i];
    return array;
}

List list = new List() { 1, 2, 3, 4, 5 };
int[] array = ConvertListToArray(list);

Or

List list = new List() { 1, 2, 3, 4, 5 };
int[] array = ConvertListToArray(list);

In that example, we didn’t explicitly provide the type parameter. This is still valid, because the compiler can infer the correct type from the usage. In our method definition, we said the first parameter must be a List<T>. We provided a List<int>. Therefore, the compiler can infer that <T> must be <int>.

Generic Classes:

Generic classes are classes that can take and keep type arguments.

public class MyNode {
    public T Data { get; set; }
    public MyNode Next { get; set; }

    public MyNode(T data) {
        Data = data;
        Next = null;
    }
}

Generic Interfaces:

In the same way that classes can be generic, interfaces also can be generic. Some perfect examples are IEnumerable<T> and IList<T>. For example’s sake, here’s an example of how we might make a custom List interface:

public interface ICustomList {
    T this[int index] { get; set; }
    T ElementAt(int index);
    void Add(T value);
    void Remove(T value);
    void Clear();
}

Generic Delegates:

Delegates can also be generic. A great example of a generic delegate would beEventHandler<TEventArgs>. This is a convenient premade delegate type for us to use with events. Here’s an example of a very common use case:

public event EventHandler SomeEvent;
protected virtual void OnSomeEvent()
{
    if (SomeEvent != null)
        SomeEvent(this, new EventArgs());
}

Default Values in Generics:

Use default keyword to assign a default valu if no value is supplied.

public static T GetDefault<T>()
{
    return default(T);
}

Conclusion

  • Use generic types to maximize code reuse, type safety, and enhance performance and make your code maintainable.
  • The most common use of generics is to create collection classes.
  • The .NET Framework class library contains several new generic collection classes in the System.Collections.Generic namespace.
  • This collection should be used whenever possible in place of classes such as ArrayList in the System.Collections namespace.
  • You can create your own custom generic interfaces, classes, methods, events and delegates.
  • Generic classes may be constrained to enable access to methods on particular data types.
  • Instantiations of parameterized classes are loaded dynamically and the code for their methods is generated on demand [Just in Time] by means of reflection.
  • Where ever possible, compiled code and data representations are shared between different instantiations.
  • Due to type specialization, the implementation never needs to box values of primitive types.
  • Strong type checking at compile time, hence more bugs caught at compile time itself.
  • Maintainability is achieved with fewer explicit conversions between data types and code with generics improves clarity and expressively.
  • Generic classes and methods combine reusability, type safety and efficiency in a way that their non-generic counterparts can never be.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s