Share This
Связаться со мной
Крути в низ
Categories
//❓ Как использовать обобщения в C# – краткая инструкция для новичков

❓ Как использовать обобщения в C# – краткая инструкция для новичков

Обобщения (generics) необходимы в тех случаях, когда мы не можем заранее знать тип данных, который будем использовать. Они есть во многих языках программирования, и сегодня мы расскажем про обобщения в C# – материал будет полезен для начинающих разработчиков.

kak ispolzovat obobshhenija v c kratkaja instrukcija dlja novichkov cfc419a - ❓ Как использовать обобщения в C# – краткая инструкция для новичков

Термины: Обобщения, обобщённые типы, шаблоны, дженерики и generics обозначают одно и то же.

Предположим, мы пишем приложение, в котором необходимо работать с данными пользователя:

         class User     {  public int  Id { get; set; }  public string Name { get; set; } }     

У класса User есть два свойства: ID – уникальный идентификатор и Name – имя пользователя. В данном случае идентификатор имеет тип данных int (целочисленный). Однако ID может быть типом string или GUID. Чтобы это предусмотреть, можно пойти одним из путей:

  • Написать много реализаций класса под каждый тип данных.
  • Использовать тип Object как универсальный тип данных.
  • Использовать обобщённые типы.

Первый вариант не подходит из-за избыточности кода. Разберём второй:

         class User {  public Object  Id { get; set; }  public string Name { get; set; } }     

Теперь используем этот класс:

         User userOne = new User{}; User userTwo = new User{};  userOne.Id = 1; userTwo.Id = "2";  int OneID = (int)userOne.Id; string TwoID = (string)userTwo.Id;  Console.WriteLine(OneID); Console.WriteLine(TwoID);     

Код отработает без ошибок, но в нем есть подводные камни. При присвоении свойству Id целочисленного значения происходит процесс упаковки (boxing):

         userOne.Id = 1; //Упаковка типа int в тип Object     

Упаковка – это неявное преобразование значения некоторого типа (например, int) к типу Object.

При получении данных обратно в переменную типа int выполняется процесс распаковки (unboxing).

         int OneID = (int)userOne.Id; //Распаковка типа Object в тип int     

Распаковка – это явное преобразование значения типа Object к некоторому другому типу. Подробнее про процессы упаковки и распаковки можно почитать в руководстве по программированию на C#.

Упаковка и распаковка ведут к снижению производительности, так как требуют затрат ресурсов системы на преобразование типов. Кроме того, такой способ не является безопасным (type safety). Если в переменную (свойство объекта) типа Object упакована строка (string), то при попытке ее распаковки в int мы получим исключение InvalidCastException.

         userTwo.Id = "2"; int TwoID = (int)userTwo.Id; // Исключение InvalidCastException     

Программа скомпилируется, а исключение выскочит во время её выполнения. Подобных ошибок можно избежать, используя обобщённые типы.

Обобщение типа

Синтаксис:

         class ClassName<T> {  public T PropertyName { get; set; } }      

Литера T (от англ. template — шаблон) в угловых скобках означает, что будет использоваться обобщение. Вместо символа T может быть выбрано любое наименование обобщения, однако такое написание считается общепринятым. Параметр в угловых скобках называется универсальным параметром.

Перепишем класс с использованием шаблона:

         class User<T> {  private T session; //Шаблон применяется к полю  public T  Id { get; set; } //Шаблон применяется к свойству  public string Name { get; set; } }     

При создании экземпляра класса вместо буквы Т нужно указать тот тип данных, который нам необходим:

         //Треугольные скобки после имени класса указывают на то, //что внутри класса будет использоваться тип int  User<int> userOne = new User<int> { };   //Треугольные скобки после имени класса указывают на то, //что внутри класса будет использоваться тип string  User<string> userTwo = new User<string> { };  userOne.Id = 1; userTwo.Id = "2";  int OneID = userOne.Id;  //При попытке присвоить переменной типа int значение типа string  //компилятор выдаст ошибку int TwoID = userTwo.Id;  Console.WriteLine(OneID); Console.WriteLine(TwoID);     

Допускается использование несколько универсальных параметров:

         class User<T, U> {  private T session; //Шаблон применяется к полю  public T  Id { get; set; } //Шаблон применяется к свойству  public U Name { get; set; } }     

Обобщения также могут быть применены к интерфейсам, классам, структурам, методам и делегатам.

         public void DoAction<T>(T ValueOne, T ValueTwo) {};     

Ограничения универсального параметра

Универсальным параметром можно типизировать любой обобщённый тип любым типом данных, однако встречаются ситуации, когда необходимо конкретизировать обобщение. Для этого используется ключевое слово where:

         class UserList<T> where T: User<int> {  T [] List = new T[10]; }     

Выражение where T: User говорит о том, что универсальный параметр T должен быть представлен классом User, или его наследником. В качестве ограничения может применяться только один класс.

Ограничением могут быть следующие типы:

  • классы;
  • интерфейсы;
  • class – универсальный параметр должен быть классом;
  • struct – универсальный параметр должен быть структурой;
  • new() – универсальный параметр должен иметь общедоступный (public) конструктор без параметров.

При использовании нескольких ограничений, задать их можно в строгом порядке:

  1. Название класса, class или struct. Эти ограничения нельзя применять одновременно.
  2. Название интерфейса.
  3. new().
         interface IUser { }  class User { }   class UserList<T> where T: User , IUser , new() { }      

Можно задать ограничения нескольким универсальным параметрам:

         class UserList<T, U, V>   where T: User   where U: new() {}      

Таким же способом можно задать ограничение обобщённых методов:

         public static void DoAction<T>(T ValueOne, T ValueTwo) where T : User {}     

Универсальный тип метода DoAction ограничен классом User или его наследником.

***

Обобщения присутствует во многих языках программирования. Шаблонизация используется фактически во всех динамических структурах языка C# (списки, очереди, стеки и т. д). Знание этого инструмента программирование поможет вам создавать более универсальные структуры и алгоритмы. Удачи в обучении!

  • 8 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован.

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Свежие комментарии

    Рубрики

    About Author 01.

    blank
    Roman Spiridonov

    Моя специальность - Back-end Developer, Software Engineer Python. Мне 39 лет, я работаю в области информационных технологий более 5 лет. Опыт программирования на Python более 3 лет. На Django более 2 лет.

    Categories 05.

    © Speccy 2022 / All rights reserved

    Связаться со мной
    Close