o7planning

C# Generics Tutorial with Examples

View more Tutorials:

Websites to learn foreign languages for free:
Follow us on our fanpages to receive notifications every time there are new articles. Facebook Twitter

1- Generics Class

The example below defines a  generics class. KeyValue is a generics class that contains pairs of key and value.
KeyValue.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
   public class KeyValue<K, V>
   {
       private K key;
       private V value;

       public KeyValue(K key, V value)
       {
           this.key = key;
           this.value = value;
       }
       public K GetKey()
       {
           return key;
       }
       public void SetKey(K key)
       {
           this.key = key;
       }
       public V GetValue()
       {
           return value;
       }
       public void SetValue(V value)
       {
           this.value = value;
       }
   }
}
K, V in  KeyValue <K, V> class  is called generics parameters which  is a certain type of data. When using this class, you must determine the specific parameter.
Take the example of using KeyValue class
KeyValueDemo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    public class KeyValueDemo
    { 
        public static void Main(string[] args)
        {
            // Create KeyValue object.
            // int: Phone Number (K = int)
            // string: Name (V = string)
            KeyValue<int, string> entry = new KeyValue<int, string>(12000111, "Tom");

            // C# understands that the return type is a int
            int phone = entry.GetKey();

            // C# understands that the return type is a string
            string name = entry.GetValue(); 
            Console.WriteLine("Phone = " + phone + " / name = " + name); 
            Console.Read();
        } 
    } 
}
Running Example:

Phone = 12000111 / name = Tom

2- Inheritance Generics class

A class extended from a generics class  can specify parameter type for generics, retain generics parameters  or add  generics parameters .
Example 1:
PhoneNameEntry.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{ 
    // This class extends KeyValue<K,V>
    // And specify the type for the K & V
    // K = int (Phone Number)
    // V = string (Name)
    public class PhoneNameEntry : KeyValue<int, string>
    { 
        public PhoneNameEntry(int key, string value)
            : base(key, value)
        {

        } 
    } 
}
Example use PhoneNameEntry:
PhoneNameEntryDemo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    public class PhoneNameEntryDemo
    { 
        public static void Main(string[] args)
        { 
            PhoneNameEntry entry = new PhoneNameEntry(12000111, "Tom");

            // C# understands that the return type is int.
            int phone = entry.GetKey();

            // C# understands that the return type is string.
            string name = entry.GetValue(); 
            Console.WriteLine("Phone = " + phone + " / name = " + name); 
            Console.Read(); 
        } 
    } 
}
Example 2:
StringAndValueEntry.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{ 
    // This class extends KeyValue<K,V>
    // Specify the parameter K is string.
    public class StringAndValueEntry<V> : KeyValue<string, V>
    { 
        public StringAndValueEntry(string key, V value)
            : base(key, value)
        {
        } 
    } 
}
Example use StringAndValueEntry class:
StringAndValueEntryDemo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    public class StringAndValueEntryDemo
    { 
        public static void main(String[] args)
        { 
            // (Emp Number, Employee Name)
            // V = string (Employee Name)
            StringAndValueEntry<String> entry = new StringAndValueEntry<String>("E001", "Tom");

            String empNumber = entry.GetKey(); 
            String empName = entry.GetValue(); 
            Console.WriteLine("Emp Number = " + empNumber);
            Console.WriteLine("Emp Name = " + empName); 
            Console.Read(); 
        }
    } 
}
Example 3:
KeyValueInfo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{ 
    // This class extends KeyValue<K,V>.
    // It has added a parameter generics I.
    public class KeyValueInfo<K, V, I> : KeyValue<K, V>
    { 
        private I info;

        public KeyValueInfo(K key, V value)
            : base(key, value)
        {
        } 
        public KeyValueInfo(K key, V value, I info)
            : base(key, value)
        {
            this.info = info;
        } 
        public I GetInfo()
        {
            return info;
        } 
        public void GetInfo(I info)
        {
            this.info = info;
        } 
    } 
}

3- Generics Interface

Interface with Generics:
GenericInterface.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
  public interface GenericInterface<G>
  {
      G DoSomething();
  }
}
For example, an implementation of the interface:
GenericInterfaceImpl.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
   public class GenericInterfaceImpl<G> : GenericInterface<G>
   {
       private G something;
       public G DoSomething()
       {
           return something;
       }
   }
}

4- Using Generics with Exception

You can create an Exception with Generics parameters.
MyException.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
   class MyException<E> : ApplicationException
   {
   }
}
Using the Generic Exception (Valid):
UsingGenericExceptionValid01.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    class UsingGenericExceptionValid01
    { 
        public void SomeMethod()
        {
            try
            {
                // ...
            }
            // Valid
            catch (MyException<string> e)
            {
                // Do something here.
            }
            // Valid
            catch (MyException<int> e)
            {
                // Do something here.
            }
            catch (Exception e)
            {
            }
        } 
    } 
}
Using the Generic Exception (Valid):
UsingGenericExceptionValid02.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    class UsingGenericExceptionValid02<K>
    {
        public void SomeMethod()
        {
            try
            {
                // ... 
            }
            // Valid
            catch (MyException<string> e)
            {
                // Do something here.
            }
            // Valid
            catch (MyException<K> e)
            {
                // Do something here.
            }
            catch (Exception e)
            {
            }
        }
    } 
}
Using the Generic Exception (Invalid):
UsingGenericExceptionInvalid.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    class UsingGenericExceptionInvalid
    {
        public void SomeMethod()
        {
            try
            {
                // ... 
            }
            // Valid
            catch (MyException<string> e)
            {
                // Do something here.
            } 
            // Invalid (Unknown parameter K) *********** 
            // catch (MyException<K> e)
            // {
                // ...            
            // }
            catch (Exception e)
            {
            }
        }
    } 
}

5- Generic Methods

A method in class or Interface may be generified. 
MyUtils.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    public class MyUtils
    {
        // <K, V>: To say that this method has two parameters K, V
        // Method returns K.
        public static K GetKey<K, V>(KeyValue<K, V> entry)
        {
            K key = entry.GetKey();
            return key;
        } 
        // <K, V>: To say that this method has two parameters K, V
        // Method returns V.
        public static V GetValue<K, V>(KeyValue<K, V> entry)
        {
            V value = entry.GetValue();
            return value;
        } 
        // List <E>: The list contains the elements of type E
        // This method returns the type E.    
        public static E GetFirstElement<E>(List<E> list, E defaultValue)
        {
            if (list == null || list.Count == 0)
            {
                return defaultValue;
            }
            E first = list.ElementAt(0);
            return first;
        } 
    } 
}
For example, using generics method :
MyUtilsDemo.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    public class MyUtilsDemo
    { 
        public static void Main(string[] args)
        { 
            // K = int: Phone
            // V = string: Name
            KeyValue<int, string> entry1 = new KeyValue<int, String>(12000111, "Tom");
            KeyValue<int, string> entry2 = new KeyValue<int, String>(12000112, "Jerry");

            // (K = int).
            int phone = MyUtils.GetKey(entry1);
            Console.WriteLine("Phone = " + phone);

            // A list containing the element type KeyValue<int, string>.
            List<KeyValue<int, string>> list = new List<KeyValue<int, string>>();

            // Add element to list
            list.Add(entry1);
            list.Add(entry2);

            KeyValue<int, string> firstEntry = MyUtils.GetFirstElement(list, null);

            if (firstEntry != null)
            {
                Console.WriteLine("Value = " + firstEntry.GetValue());
            } 
            Console.Read();
        } 
    } 
}
Running example:

Phone = 12000111
Value = Tom

6- Generic Object Initialization

Sometimes, you want to initialize a Generic object:

public void DoSomething<T>()
{ 
     // Generic Object Initialization
     T t = new T(); // Error 
}
The cause is T parameter is unlikely that it has constructor T(), so you need to add  when T: new() constraints. See the example below:
GenericInitializationExample.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    class GenericInitializationExample 
    {
        // Type T must have default constructor.
        public void DoSomeThing<T>()
            where T : new()
        {
            T t = new T();
        } 
        // Type K must have default constructor.
        // and extends KeyValue<K,string>
        public void ToDoSomeThing<K>()
            where K: KeyValue<K,string>, new( )
        {
            K key = new K();
        }  
        public T DoDefault<T>()
        {
            // Return null if T is reference type
            // or return 0 if T is number (int, float,..) 
            return default(T);
        }
    } 
}

7- Generic Array

In C # you can declare an array of generics:

// Initialize an array.
T[] myArray = new T[10];
GenericArrayExample.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
   class GenericArrayExample
   {
       public static T[] FilledArray<T>(T value, int count)
       {
           T[] ret = new T[count];
           for (int i = 0; i < count; i++)
           {
               ret[i] = value;
           }
           return ret;
       }
       public static void Main(string[] args)
       {
           string value = "Hello"; 
           string[] filledArray = FilledArray<string>(value, 10);
           foreach (string s in filledArray)
           {
               Console.WriteLine(s);
           }
       }
   }
}

View more Tutorials: