devstory

Le Tutoriel de C# Generics

  1. La classe Generics
  2. La classe générique d'héritage
  3. Interface Generics
  4. L'utilisation de Generic avec Exception
  5. Des méthodes generics
  6. L'initialisation des objets Generic
  7. Le tableau Generic

1. La classe Generics

L'exemple ci-dessous définit une classe générique. KeyValue est une classe générique qui contient des paires de clés et de valeur (key/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 dans la classe KeyValue<K,V> est appelé des paramètres génériques qui est un certain type de données. Lorsque vous utilisez cette classe, vous devez déterminer le paramètre spécifique.
Prennez l'exemple de l'utilisation la classe KeyValue.
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)
        {
            // Créez un objet KeyValue.
            // int: Numéro de téléphone  (K = int)
            // string: Nom d'utilisateur.  (V = string).
            KeyValue<int, string> entry = new KeyValue<int, string>(12000111, "Tom");

            // C# comprend que le type rendu est int (K = int).
            int phone = entry.GetKey();

            // C# comprend que le type rendu est string (V = string).
            string name = entry.GetValue(); 
            Console.WriteLine("Phone = " + phone + " / name = " + name); 
            Console.Read();
        } 
    } 
}
L'exécution de l'exemple:
Phone = 12000111 / name = Tom

2. La classe générique d'héritage

Une classe étendue à partir d'une classe générique peut spécifier un type de paramètre pour les génériques, conserver les paramètres génériques ou ajouter des paramètres génériques.
Exemple 1:
PhoneNameEntry.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{ 
    // Cette classe étend de la classe KeyValue<K,V>
    // Et précise le type de deux paramètres K & V
    // K = int  (Numéro de téléphone).
    // V = string   (Nom d'utilisateur).
    public class PhoneNameEntry : KeyValue<int, string>
    { 
        public PhoneNameEntry(int key, string value)
            : base(key, value)
        {

        } 
    } 
}
L'exemple utilise 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# comprend que le type rendu est int.
            int phone = entry.GetKey();

            // C# comprend que le type rendu est string.
            string name = entry.GetValue(); 
            Console.WriteLine("Phone = " + phone + " / name = " + name); 
            Console.Read(); 
        } 
    } 
}
Exemple 2:
StringAndValueEntry.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{ 
    // Cette classe étend de la classe KeyValue<K,V>
    // Spécifie le type du paramètre K est String.
    // Garde le type du paramètre generic V.
    public class StringAndValueEntry<V> : KeyValue<string, V>
    { 
        public StringAndValueEntry(string key, V value)
            : base(key, value)
        {
        } 
    } 
}
L'exemple utilise la classe StringAndValueEntry:
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(); 
        }
    } 
}
Exemple 3:
KeyValueInfo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{ 
    // Cette classe étend de la classe KeyValue<K,V>.
    // Ella a ajouté un paramètre 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. Interface Generics

Une Interface a le paramètre 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();
  }
}
Par exemple: Une classe emt en oeuvre (implements) de l'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. L'utilisation de Generic avec Exception

Vous pouvez créer une Exception avec des paramètres Generics.
MyException.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
   class MyException<E> : ApplicationException
   {
   }
}
L'utilisation Generic Exception valide:
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)
            {
                // Fait quelque chose ici.
            }
            // Validé
            catch (MyException<int> e)
            {
                // Fait quelque chose ici.              
            }
            catch (Exception e)
            {
            }
        } 
    } 
}
L'utilisation de Generics Exception valide:
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)
            {
                // Fait quelque chose ici.
            }
            // Validé
            catch (MyException<K> e)
            {
                // Fait quelque chose ici.              
            }
            catch (Exception e)
            {
            }
        }
    } 
}
L'utilisation Generics Exception invalide:
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)
            {
                // Fait quelque chose ici.
            } 
            // Invalid (Unknown parameter K) *********** 
            // catch (MyException<K> e)
            // {
                // ...            
            // }
            catch (Exception e)
            {
            }
        }
    } 
}

5. Des méthodes generics

Une méthode en classe ou en Interface peut être générée (generify).
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;
        } 
    } 
}
Par exemple, l'utilisation la méthode generics:
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);

            // Une liste contenant le type d'élément KeyValue<int,string>.
            List<KeyValue<int, string>> list = new List<KeyValue<int, string>>();

            // Ajoutez des éléments à la liste.
            list.Add(entry1);
            list.Add(entry2);

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

            if (firstEntry != null)
            {
                Console.WriteLine("Value = " + firstEntry.GetValue());
            } 
            Console.Read();
        } 
    } 
}
L'exécution de l'exemple:
Phone = 12000111
Value = Tom

6. L'initialisation des objets Generic

Parfois, vous souhaitez initialiser un objet Generic:
public void DoSomething<T>()
{ 
     // Initialisation d'objet Generic
     T t = new T(); // Error 
}
La cause est que le paramètre T est peu probable qu'il ait le constructeur (constructor) T(), donc vous devez ajouter des contraintes when T : new(). Voyez l'exemple ci-dessous:
GenericInitializationExample.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    class GenericInitializationExample 
    {
        // Le type T doit avoir un Constructeur par défaut.
        public void DoSomeThing<T>()
            where T : new()
        {
            T t = new T();
        } 
        // Le type K doit avoir un Constructeur par défaut
        // et étend de la classe KeyValue.
        public void ToDoSomeThing<K>()
            where K: KeyValue<K,string>, new( )
        {
            K key = new K();
        }  
        public T DoDefault<T>()
        {
            // Renvoie null si T est le type de référence (reference type).
            // Hoặc 0 nếu T là kiểu số  (int, float,..)
            return default(T);
        }
    } 
}

7. Le tableau Generic

Dans C# vous pouvez déclarer un tableau Generics:
// Initialisez un tableau.
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);
           }
       }
   }
}