betacode

Руководство C# Generics

  1. Класс Generics
  2. Наследование класса Generics
  3. Interface Generics
  4. Использование Generic с Exception
  5. Метод generics
  6. Инициализация объекта Generic
  7. Массив Generic

1. Класс Generics

Пример ниже дает определение классу generics. KeyValue это класс generics, который содержит пару ключей и значение (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 в классе KeyValue<K,V> называются параметрами generics, это определенный вид данных. При использовании этого класса, вам нужно опредеилть конкретный параметр.
Посмотрим пример использования класса 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)
        {
            // Создать объект KeyValue.
            // int: Номер телефона  (K = int)
            // string: Имя пользователя.  (V = string).
            KeyValue<int, string> entry = new KeyValue<int, string>(12000111, "Tom");

            // C# понимает возвращенный вид как int (K = int).
            int phone = entry.GetKey();

            // C# понимает возвращенный вид как string (V = string).
            string name = entry.GetValue(); 
            Console.WriteLine("Phone = " + phone + " / name = " + name); 
            Console.Read();
        } 
    } 
}
Запуск примера:
Phone = 12000111 / name = Tom

2. Наследование класса Generics

Расширенный класс из класса generics, который может определить вид параметра для generics, оставить параметры generics или добавить параметры generics.
Пример 1:
PhoneNameEntry.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{ 
    // Данный класс расширен из класса KeyValue<K,V>
    // И ясно определяет вид для 2 параметров K & V
    // K = int  (Номер телефона).
    // V = string   (Имя пользователя).
    public class PhoneNameEntry : KeyValue<int, string>
    { 
        public PhoneNameEntry(int key, string value)
            : base(key, value)
        {

        } 
    } 
}
Пример использования 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# понимает возвращенный вид как int.
            int phone = entry.GetKey();

            // C# понимает возвращенный вид как 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
{ 
    // Данный класс расширен из класса KeyValue<K,V>
    // Ясно определить параметр K как String.
    // Оставить вид параметра generic V.
    public class StringAndValueEntry<V> : KeyValue<string, V>
    { 
        public StringAndValueEntry(string key, V value)
            : base(key, value)
        {
        } 
    } 
}
Пример использования класса 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)
        { 
            // (Код сотрудника, Имя сотрудника).
            // V = string (Имя сотрудника)
            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(); 
        }
    } 
}
Пример 3:
KeyValueInfo.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{ 
    // Данный класс расширен из класса KeyValue<K,V>.
    // Он имеет еще один параметр 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

Interface с параметром 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();
  }
}
Например, класс выполняет (implements) 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. Использование Generic с Exception

Вы можете определить Exception с параметрами 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
   {
   }
}
Использование действительного Generic Exception:
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
            {
                // ...
            }
            // Действительно
            catch (MyException<string> e)
            {
                // Сделать что-то здесь.
            }
            // Действительно
            catch (MyException<int> e)
            {
                // Сделать что-то здесь.         
            }
            catch (Exception e)
            {
            }
        } 
    } 
}
Использование действительного Generic Exception:
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
            {
                // ... 
            }
            // Действительно
            catch (MyException<string> e)
            {
                // Сделать что-то здесь.
            }
            // Действительно
            catch (MyException<K> e)
            {
                // Сделать что-то здесь.
            }
            catch (Exception e)
            {
            }
        }
    } 
}
Использование недействительного Generic Exception:
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
            {
                // ... 
            }
            // Действительно
            // ​​​​​​​
            catch (MyException<string> e)
            {
                // Сделать что-то здесь.
            } 
            // Invalid (Unknown parameter K) *********** 
            // catch (MyException<K> e)
            // {
                // ...            
            // }
            catch (Exception e)
            {
            }
        }
    } 
}

5. Метод generics

Метод в класс или интерфейсе может быть стать Generic (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> : Говорит этот метод имеет 2 вида параметра K,V
        // Метод возвращает вид K.
        public static K GetKey<K, V>(KeyValue<K, V> entry)
        {
            K key = entry.GetKey();
            return key;
        } 
        // <K,V> : Говорит этот метод имеет 2 вида параметра K,V
        // Метод возвращает вид V.
        public static V GetValue<K, V>(KeyValue<K, V> entry)
        {
            V value = entry.GetValue();
            return value;
        } 
        // List<E>: Список содержит элементы вида E
        // Данный метод возвращает вид 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;
        } 
    } 
}
Пример использования метода 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);

            // Списко содержит элементы вида KeyValue<int,string>.
            List<KeyValue<int, string>> list = new List<KeyValue<int, string>>();

            // Добавить элемент в список.
            list.Add(entry1);
            list.Add(entry2);

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

            if (firstEntry != null)
            {
                Console.WriteLine("Value = " + firstEntry.GetValue());
            } 
            Console.Read();
        } 
    } 
}
Запуск примера:
Phone = 12000111
Value = Tom

6. Инициализация объекта Generic

Иногда вы хотите инициализировать объект Generic:
public void DoSomething<T>()
{ 
     // Инициализировать объект Generic
     T t = new T(); // Error 
}
Причина ошибки выше, является то, что параметр Т возможно не имеет конструктор (constructor) T(), поэтому ам нужно добавить принуждение when T : new(). Посмотрим пример ниже:
GenericInitializationExample.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTutorial
{
    class GenericInitializationExample 
    {
        // Вид T должен быть видом, имеющим Constructor по умолчанию.
        public void DoSomeThing<T>()
            where T : new()
        {
            T t = new T();
        } 
        // Вид T должен быть видом, имеющим Constructor по умолчанию.
        // и расширенным из класса KeyValue.
        public void ToDoSomeThing<K>()
            where K: KeyValue<K,string>, new( )
        {
            K key = new K();
        }  
        public T DoDefault<T>()
        {
            // Возвращает null если T является ссылочным видом (reference type).
            // Или 0 если T является видом числа  (int, float,..)
            return default(T);
        }
    } 
}

7. Массив Generic

В C# вы можете объявить массив Generics:
// Инициализировать массив.
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);
           }
       }
   }
}

Pуководства C#

Show More