Generics In C#


This article discusses the details of generics concept of C# and also will explain in detail about how they are implemented, the benefits of the programming model, and unique innovations, such as constrains, generic methods and generic inheritance. In addition I have also discussed about how the .NET Framework utilizes generics.

What are Generics?

Generics are the most powerful feature of C#.

Generics allow you to define type-safe data structures, without committing to actual data types. This results in a significant performance boost and higher quality code, because you get to reuse data processing algorithms without duplicating type-specific code.

            Source: Code collections web site

Generics are similar to C++ templates, but are drastically different in implementation and capabilities. This article discusses the problem space generics address, how they are implemented, the benefits of the programming model, and unique innovations, such as constrains, generic methods and delegates, and generic inheritance. You will also see how generics are utilized in other areas of the .NET Framework such as reflection, arrays, collections, serialization, and remoting, and how to improve on the basic offering.

Generic Assembly

The generic is a type of collection and which is available as the part of Collection namespace assembly.

Generics allow you to delay the specification of the data type of programming elements in a class or a method, until it is actually used in the program. In other words, generics allow you to write a class or method that can work with any data type.

You write the specifications for the class or the method, with substitute parameters for data types. When the compiler encounters a constructor for the class or a function call for the method, it generates code to handle the specific data type. A simple example would help understanding the concept.

Creating Generic List<T> Collections

Generic List collection is similar to arrays. You declare the List, populate its members, and then access the members. Here's a code example of how to use a List.

Sample Generic List <int>
List<int> myValue = new List<int>();
Sample Generic List <string>
List<string> myValue = new List<string>();

The above two codes can be replaced by a single line of code using Generics concept.

List<T> myValue = new List<T>();

Based on the usage, the [T] will behave as either “int” or “string” or any data type based on the executing application usage.

Generics Features

Generics has the best features which can make your application better by its operations, Generics will maximize code reuse, type safety, and performance.

You can create generic collection classes. The .NET Framework class library contains several new generic collection classes in the System.Collections.Generic namespace as discussed earlier.

You may use these generic collection classes instead of the collection classes in the System.Collections namespace.
You can create your own generic interfaces, classes, methods, events, and delegates.

You may create generic classes constrained to enable access to methods on particular data types.

You may get information on the types used in a generic data type at run-time by means of reflection.

Benefits of using Generics

Generics in .NET let you reuse code and the effort you put into implementing it. The types and internal data can change without causing code bloat, regardless of whether you are using value or reference types. You can develop, test, and deploy your code once, reuse it with any type, including future types, all with full compiler support and type safety.

The generic code does not force the boxing and unboxing of value types, or the down casting of reference types, performance is greatly improved.

With value types there is typically a 200 percent performance gain, and with reference types you can expect up to a 100 percent performance gain in accessing the type (of course, the application as a whole may or may not experience any performance improvements).

The source code available with this article includes a micro-benchmark application, which executes a stack in a tight loop. The application lets you experiment with value and reference types on an Object-based stack and a generic stack, as well as changing the number of loop iterations to see the effect generics have on performance.

Sample Generics and Usage of Generics

  1. using System;  
  2. using System.Collections.Generic;  
  3. namespace GenericSampleApp  
  4. {  
  5.     /// <summary>  
  6.     /// SampleGenericArray  
  7.     /// </summary>  
  8.     /// <typeparam name="T"></typeparam>  
  9.     public class SampleGenericArray < T >   
  10.       {  
  11.         private T[] array;  
  12.         /// <summary>  
  13.         /// SampleGenericArray - Constructor  
  14.         /// </summary>  
  15.         /// <param name="size">size</param>  
  16.         public SampleGenericArray(int size)   
  17.       {  
  18.             array = new T[size + 1];  
  19.         }  
  20.         /// <summary>  
  21.         /// getMyItem - Get Property to return the value  
  22.         /// </summary>  
  23.         /// <param name="index">index</param>  
  24.         /// <returns></returns>  
  25.         public T getMyItem(int index)  
  26.         {  
  27.             return array[index];  
  28.         }  
  29.         /// <summary>  
  30.         /// setMyItem - Set the Property to set value  
  31.         /// </summary>  
  32.         /// <param name="index">index</param>  
  33.         /// <param name="value">value</param>  
  34.         public void setMyItem(int index, T value)  
  35.         {  
  36.             array[index] = value;  
  37.         }  
  38.     }  
  39.     public class SampleTest {  
  40.         /// <summary>  
  41.         /// Main  
  42.         /// </summary>  
  43.         /// <param name="args"></param>  
  44.         public static void Main(string[] args) {  
  45.             //Declaring an int array  
  46.             SampleGenericArray < int > intArray = new SampleGenericArray < int > (5);  
  47.             //Setting up of values  
  48.             for (int c = 0; c < 5; c++) {  
  49.                 intArray.setMyItem(c, c * 5);  
  50.             }  
  51.             //Retrieving the values  
  52.             for (int c = 0; c < 5; c++) {  
  53.                 Console.Write(intArray.getMyItem(c) + " ");  
  54.             }  
  55.             Console.WriteLine();  
  56.             //Declaring a character array  
  57.             SampleGenericArray < char > charArray = new SampleGenericArray < char > (5);  
  58.             //Setting values  
  59.             for (int c = 0; c < 5; c++) {  
  60.                 charArray.setMyItem(c, (char)(c + 97));  
  61.             }  
  62.             //Retrieving the values  
  63.             for (int c = 0; c < 5; c++) {  
  64.                 Console.Write(charArray.getMyItem(c) + " ");  
  65.             }  
  66.             Console.WriteLine();  
  67.             Console.ReadKey();  
  68.         }  
  69.     }  
  70. }