Skip Navigation Links

 CodeMatrixThe ultimate site for .NET programmers

Skip Navigation Links.    

Generics in C#

Generics introduce to the .NET Framework the concept of type parameters, which make it possible to design classes and methods that defer the specification of one or more types until the class or method is declared and instantiated by client code.

Generics provide the following advantages:
Generics maximize code reuse, provide type safety, and enhance performance.
Generics can be used to create collection classes.
Generics enable programmers to create generic interfaces, classes, methods, events and delegates.
Generic classes may be constrained to enable access to methods on particular data types.

What is the problem if no generics are available?

In .NET 1.1, the type safe falls apart when you use collections. All types are derived from Object, and every type can be put into the collection. This will lead no type checking at all.
Every time an object is taken out of a collection you must cast it to the correct type, which causes a performance hit and ugly code. In addition, if you add a value type (i.e., integer) to the collection also decreases the performance because of boxing and unboxing.

Let me explain this problem more eloquently with the help of a linked list example. To create our simplified linked list, we'll need three classes:
1. The Node class, to contain the data and the reference to the next Node
2. The LinkedList class, to contain the first Node in the list and any additional information about the list
3. The test application, to exercise the LinkedList class

Linked list without generics:

public class Customer
{
    private string name;
    public Customer(string name)
    {
        this.name = name;
    }
    public override string ToString()
    {
        return this.name;
    }
}
public class Node
{
    Object data;
    Node next;
    public Node(Object data)
    {
        this.data = data;
        this.next = null;
    }
    public Object Data
    {
        get { return this.data; }
        set { data = value; }
    }
    public Node Next
    {
        get { return this.next; }
        set { this.next = value; }
    }
    public void Append(Node newNode)
    {
        if (this.next == null)
        {
            this.next = newNode;
        }
        else
        {
            next.Append(newNode);
        }
    }
    public override string ToString()
    {
        string output = data.ToString();
        if (next != null)
        {
            output += ", " + next.ToString();
        }
        return output;
    }
}
public class LinkedList
{
    Node headNode = null;

    public void Add(Object data)
    {
        if (headNode == null)
        {
            headNode = new Node(data);
        }
        else
        {
            headNode.Append(new Node(data));
        }
    }
    public object this[int index]
    {
        get
        {
            int ctr = 0;
            Node node = headNode;
            while (node != null && ctr <= index)
            {
                if (ctr == index)
                {
                    return node.Data;
                }
                else
                {
                    node = node.Next;
                }
                ++ctr;
            } // end while
            return null;
        }    // end get
    }      // end indexer
    public override string ToString()
    {
        if (this.headNode != null)
        {
            return this.headNode.ToString();
        }
        else
        {
            return string.Empty;
        }
    }
}
public void Run()
{
    LinkedList ll = new LinkedList();
    for (int i = 0; i < 10; i++)
    {
        ll.Add(i);
    }
    Console.WriteLine(ll);
    Console.WriteLine("  Done. Adding Customers...");

    ll.Add(new Customer("Beau"));
    ll.Add(new Customer("Don"));
    ll.Add(new Customer("George"));
    ll.Add(new Customer("Jeff"));

    Console.WriteLine(ll);
    Console.WriteLine("  Done.");
}

Console.WriteLine("The fourth integer is " + Convert.ToInt32(ll[3]));
Customer d = (Customer) ll[11];
Console.WriteLine("The second Customer is " + d);
Also, as noted above, when you want to retrieve the items from your list, the integers must be explicitly unboxed (cast to integers) and the Customers must be cast to Customer objects.
The solution to all of these problems is to create type-specific collections.

Linked list with generics:

Generics thus allow you to create type-safe collections without having to duplicate code. Even better, because the generic types are expanded to their specific types at run time, the Just In Time compiler is able to share code among different instances, dramatically reducing the code.


public class Node
{
    T data;
    Node next;
    public Node(T data)
    {
        this.data = data;
        this.next = null;
    }
    public Node Next
    {
        get { return this.next; }
        set { this.next = value; }
    }
    public void Append(Node newNode)
    {
        if (this.next == null)
        {
            this.next = newNode;
        }
        else
        {
            next.Append(newNode);
        }
    }

    public override string ToString()
    {
        string output = data.ToString();
        if (next != null)
        {
            output += ", " + next.ToString();
        }
        return output;
    }
}
public class LinkedList
{
    Node headNode = null;
    public void Add(T data)
    {
        if (headNode == null)
        {
            headNode = new Node(data);
        }
        else
        {
            headNode.Append(new Node(data));
        }
    }
    public object this[int index]
    {
        get
        {
            int ctr = 0;
            Node node = headNode;
            while (node != null && ctr <= index)
            {
                if (ctr == index)
                {
                    return node;
                }
                else
                {
                    node = node.Next;
                }
                ++ctr;
            } // end while
            return null;
        }    // end get
    }      // end indexer
    public override string ToString()
    {
        if (this.headNode != null)
        {
            return this.headNode.ToString();
        }
        else
        {
            return string.Empty;
        }
    }
}
public void Run()
{
    LinkedList ll = new LinkedList();
    for (int i = 0; i < 10; i++)
    {
        ll.Add(i);
    }
    Console.WriteLine(ll);
    Console.WriteLine("  Done. Adding Customers...");

    LinkedList customers = new LinkedList();

    customers.Add(new Customer("Beau"));
    customers.Add(new Customer("Don"));
    customers.Add(new Customer("George"));
    customers.Add(new Customer("Jeff"));

    Console.WriteLine(ll);
    Console.WriteLine("  Done.");
}
Downloads
The source code in this article can be downloaded from below link. The code is complied with Microsoft Visual C# 2008.

Copyright © 2008 www.codematrix.net, All Rights Reserved. Disclaimer