C#: Generics – подробнее

Spread the love

Тип ссылочных данных Generics (обобщения) требует более детального рассмотрения в связи с тем, что содержит в себе множество элементов.

Ранее мы затронули раскрытие информации касательно этого типа ссылочных данных, однако затронули не все аспекты этого элемента языка программирования C#.

Пришло время раскрыть такие понятия, как Must Have, Extended, Custom, которые являются как частями понятия Generics (обобщения), так и в свою очередь включают в себя некоторые понятия, с которыми нам предстоит познакомиться.

Итак, начнём с Must Have.

Понятие “Must Have” (Следует иметь или Должно быть) обычно относится к основным или незаменимым предметам или функциям. В контексте разработки программного обеспечения или программирования вот некоторые часто упоминаемые элементы “Must Have”:

1. Интегрированная среда разработки (IDE): Надежная и многофункциональная среда разработки необходима для написания, отладки и тестирования кода. Популярные варианты для разработки на C# включают Visual Studio, Visual Studio Code и JetBrains Rider.

100000R, 12%, 1 year

2. Компилятор и среда выполнения: Для компиляции и запуска кода на C# вам понадобится .NET Framework или .NET Core runtime, в зависимости от вашей целевой платформы. Они предоставляют необходимые библиотеки и среду выполнения для приложений на C#.

3. Библиотеки и фреймворки: Надежная коллекция библиотек и фреймворков имеет решающее значение для эффективной разработки. Это включает в себя библиотеку классов .NET Framework, ASP.NET для веб-разработки, Xamarin для кроссплатформенной мобильной разработки и Unity для разработки игр.

4. Система контроля версий (VCS): Использование VCS, такой как Git, необходимо для отслеживания изменений, совместной работы с другими пользователями и управления репозиториями кода. Это позволяет вам возвращаться к предыдущим версиям, разветвлять код и эффективно объединять изменения.

5. Фреймворки тестирования: Внедрение модульных тестов и автоматизированного тестирования имеет решающее значение для обеспечения качества и надежности вашего кода. Популярные фреймворки тестирования на C# включают NUnit, MSTest и xUnit.

6. Инструменты документирования: Создание всеобъемлющей и актуальной документации жизненно важно для сопровождения кода и обмена знаниями. Такие инструменты, как комментарии к документации XML и автоматизированные генераторы документации (например, Doxygen, Sandcastle), помогают создавать хорошо документированные базы кода.

7. Менеджеры пакетов: Менеджеры пакетов, такие как NuGet (для .NET Framework) и NuGet Package Manager (для .NET Core), упрощают процесс управления и интеграции внешних библиотек и зависимостей в ваши проекты.

8. Средства отладки: Отладчики необходимы для выявления и устранения проблем в вашем коде. Встроенные возможности отладки IDE, таких как Visual Studio, предоставляют мощные средства отладки, включая точки останова, пошаговое выполнение и окна просмотра.

9. Поддержка сообщества: Взаимодействие с сообществом программистов имеет неоценимое значение для обмена знаниями, устранения неполадок и ознакомления с передовыми практиками. Онлайн-платформы, такие как Stack Overflow, форумы и группы в социальных сетях, предоставляют доступ к обширным знаниям и поддержке.

Помните, что конкретные элементы “Must Have” могут варьироваться в зависимости от ваших конкретных требований к проекту, целевой платформы и личных предпочтений. Важно постоянно изучать и оценивать инструменты, библиотеки и фреймворки, чтобы найти те, которые наилучшим образом соответствуют вашим потребностям.

Одним из элементов Must Have является класс List.

Приведём пример того, как вы можете использовать класс List<T> в C#:

using System;

using System.Collections.Generic;

class Program

{

    static void Main()

    {

        // Create a new list to store integers

        List<int> numbers = new List<int>();

        // Add elements to the list

        numbers.Add(10);

        numbers.Add(20);

        numbers.Add(30);

        // Accessing elements in the list

        Console.WriteLine(“First element: ” + numbers[0]); // Output: 10

        // Modifying elements in the list

        numbers[1] = 50;

        // Removing elements from the list

        numbers.RemoveAt(2);

        // Iterate over the list using a foreach loop

        foreach (int number in numbers)

        {

            Console.WriteLine(number);

        }

    }

}

В этом примере мы создаем список<int> с именем numbers для хранения целых чисел. Мы добавляем элементы в список с помощью метода Add, изменяем элементы, присваивая новые значения определенным индексам, и удаляем элементы с помощью метода RemoveAt. Мы получаем доступ к элементам с помощью оператора индексации [] и выполняем итерацию по списку, используя цикл foreach.

Класс List<T> является частью пространства имён System.Collections.Generic и предоставляет динамическое изменение размера и другие полезные методы для работы с коллекциями элементов.

Это позволяет вам гибко и эффективно добавлять, удалять, получать доступ и изменять элементы.

Обратите внимание, что T в List<T> представляет параметр типа, что означает, что вы можете использовать класс List<T> с различными типами, такими как List<string> для хранения строк или List<double> для хранения двойных значений.

Ещё одним элементом “Must Have” является класс Dictionary<TKey, TValue>.

Вот пример того, как вы можете использовать класс Dictionary<TKey, TValue> в C#:

using System;

using System.Collections.Generic;

class Program

{

    static void Main()

    {

        // Create a new dictionary to store student grades

        Dictionary<string, int> studentGrades = new Dictionary<string, int>();

        // Add key-value pairs to the dictionary

        studentGrades.Add(“John”, 85);

        studentGrades.Add(“Emily”, 92);

        studentGrades.Add(“Adam”, 78);

        // Accessing values using keys

        Console.WriteLine(“John’s grade: ” + studentGrades[“John”]); // Output: 85

        // Modifying values in the dictionary

        studentGrades[“Emily”] = 95;

        // Removing key-value pairs from the dictionary

        studentGrades.Remove(“Adam”);

        // Iterating over the dictionary using a foreach loop

        foreach (KeyValuePair<string, int> kvp in studentGrades)

        {

            Console.WriteLine(kvp.Key + “: ” + kvp.Value);

        }

    }

}

В этом примере мы создаем словарь<string, int> с именем studentGrades для хранения имен учащихся в виде ключей (типа string) и соответствующих им оценок в виде значений (типа int). Мы добавляем пары ключ-значение в словарь с помощью метода Add, изменяем значения, присваивая новые значения определенным ключам, и удаляем пары ключ-значение с помощью метода Remove. Мы получаем доступ к значениям, используя ключи в квадратных скобках [], и выполняем итерацию по словарю, используя цикл foreach с KeyValuePair<TKey, TValue>.

Класс Dictionary<TKey, TValue> является частью System.Collections.Generic пространства имён и предоставляет структуру данных сопоставления ключ-значение. Это позволяет вам эффективно хранить, получать доступ, изменять и удалять элементы на основе их ключей. Он обеспечивает быстрый поиск и извлечение значений на основе ключей, что делает его подходящим для сценариев, где вам нужно связать уникальные ключи с соответствующими значениями.

Обратите внимание, что TKey и TValue в Dictionary<TKey, TValue> представляют параметры типа, что означает, что вы можете использовать класс Dictionary<TKey, TValue> с разными типами ключей и значений. Например, у вас может быть словарь<int, string>, где целые числа используются в качестве ключей, а строки – в качестве значений.

Наряду с теми элементами, которые относятся к “Must Have”, в C# используются элементы Extended (элементы расширенных возможностей).

Приведём пример использования класса Dictionary<TKey, TValue> в C#, который демонстрирует дополнительные операции и возможности:

“`csharp

using System;

using System.Collections.Generic;

class Program

{

    static void Main()

    {

        // Create a new dictionary to store book information

        Dictionary<string, string> bookInfo = new Dictionary<string, string>();

        // Add key-value pairs to the dictionary

        bookInfo.Add(“ISBN123”, “Title: The Catcher in the Rye, Author: J.D. Salinger”);

        bookInfo.Add(“ISBN456”, “Title: To Kill a Mockingbird, Author: Harper Lee”);

        bookInfo.Add(“ISBN789”, “Title: 1984, Author: George Orwell”);

        // Accessing values using keys

        Console.WriteLine(“Book information for ISBN123: ” + bookInfo[“ISBN123”]); // Output: Title: The Catcher in the Rye, Author: J.D. Salinger

        // Modifying values in the dictionary

        bookInfo[“ISBN456”] = “Title: Pride and Prejudice, Author: Jane Austen”;

        // Removing key-value pairs from the dictionary

        bookInfo.Remove(“ISBN789”);

        // Checking if a key exists in the dictionary

        bool containsKey = bookInfo.ContainsKey(“ISBN123”);

        Console.WriteLine(“Contains ISBN123? ” + containsKey); // Output: True

        // Retrieving the number of key-value pairs in the dictionary

        int count = bookInfo.Count;

        Console.WriteLine(“Number of books: ” + count); // Output: 2

        // Iterating over the dictionary using a foreach loop

        foreach (KeyValuePair<string, string> kvp in bookInfo)

        {

            Console.WriteLine(“ISBN: ” + kvp.Key + “, ” + kvp.Value);

        }

    }

}

“`

В этом расширенном примере мы расширяем предыдущее использование `Dictionary<TKey, TValue>`.

Мы добавляем пары ключ-значение, представляющие информацию о книге, используя уникальные номера ISBN в качестве ключей и сведения о книге в качестве значений. Мы демонстрируем изменение значений, удаление пар ключ-значение, проверку наличия ключа и извлечение количества пар ключ-значение. В примере также демонстрируется итерация по словарю с использованием цикла foreach и доступ как к ключам, так и к значениям с помощью KeyValuePair<TKey, TValue>.

То есть в этом расширенном примере показаны дополнительные функциональные возможности и операции, доступные с классом Dictionary<TKey, TValue>, в частности, демонстрируются некоторые распространенные варианты использования, такие как хранение коллекций данных и управление ими с использованием ассоциаций ключ-значение.

В свою очередь элементы Extended (элементы расширенных возможностей) включают в себя такие понятия как Stack, Queue, Linked list.

Рассмотрим, как вы можете использовать класс Stack<T> в C#:

“`csharp

using System;

using System.Collections.Generic;

class Program

{

    static void Main()

    {

        // Create a new stack to store integers

        Stack<int> numberStack = new Stack<int>();

        // Push elements onto the stack

        numberStack.Push(10);

        numberStack.Push(20);

        numberStack.Push(30);

        // Accessing the top element of the stack

        int topElement = numberStack.Peek();

        Console.WriteLine(“Top element: ” + topElement); // Output: 30

        // Removing and retrieving elements from the stack

        int poppedElement = numberStack.Pop();

        Console.WriteLine(“Popped element: ” + poppedElement); // Output: 30

        // Checking if the stack contains a specific element

        bool containsElement = numberStack.Contains(20);

        Console.WriteLine(“Contains 20? ” + containsElement); // Output: True

        // Checking the number of elements in the stack

        int count = numberStack.Count;

        Console.WriteLine(“Number of elements: ” + count); // Output: 2

        // Iterating over the stack using a foreach loop

        foreach (int number in numberStack)

        {

            Console.WriteLine(number);

        }

    }

}

“`

В этом примере мы создаем Stack <int>, называемый number Stack, для хранения целых чисел.

Мы используем метод Push для добавления элементов в стек, метод Peek для доступа к верхнему элементу без его удаления и метод Pop для удаления и извлечения верхнего элемента из стека. Мы также демонстрируем использование метода Contains для проверки наличия определенного элемента в стеке. Мы извлекаем количество элементов, используя свойство Count, и выполняем итерацию по стеку, используя цикл foreach.

Класс Stack<T> является частью пространства имён `System.Collections.Generic` и предоставляет коллекцию Last-In-First-Out (LIFO).

Это позволяет вам добавлять элементы в верхнюю часть стека, получать доступ к самому верхнему элементу и удалять его, а также эффективно выполнять различные операции, связанные со стеком.

Обратите внимание, что T в Stack<T> представляет параметр типа, что означает, что вы можете использовать класс Stack<T> с различными типами, такими как Stack<string> для хранения строк или Stack<double> для хранения двойных значений.

Рассмотрим применение класса Queue<T> в C#:

“`csharp

using System;

using System.Collections.Generic;

class Program

{

    static void Main()

    {

        // Create a new queue to store strings

        Queue<string> stringQueue = new Queue<string>();

        // Enqueue elements into the queue

        stringQueue.Enqueue(“Apple”);

        stringQueue.Enqueue(“Banana”);

        stringQueue.Enqueue(“Orange”);

        // Accessing the front element of the queue

        string frontElement = stringQueue.Peek();

        Console.WriteLine(“Front element: ” + frontElement); // Output: Apple

        // Dequeuing and retrieving elements from the queue

        string dequeuedElement = stringQueue.Dequeue();

        Console.WriteLine(“Dequeued element: ” + dequeuedElement); // Output: Apple

        // Checking if the queue contains a specific element

        bool containsElement = stringQueue.Contains(“Banana”);

        Console.WriteLine(“Contains Banana? ” + containsElement); // Output: True

        // Checking the number of elements in the queue

        int count = stringQueue.Count;

        Console.WriteLine(“Number of elements: ” + count); // Output: 2

        // Iterating over the queue using a foreach loop

        foreach (string item in stringQueue)

        {

            Console.WriteLine(item);

        }

    }

}

“`

В этом примере мы создаем очередь Queue<string>, называемую string Queue, для хранения строк. Мы используем метод Enqueue для добавления элементов в конец очереди, метод Peek для доступа к переднему (первому) элементу без его удаления и метод Dequeue для удаления и извлечения переднего элемента из очереди. Мы также демонстрируем использование метода Contains для проверки наличия определенного элемента в очереди. Мы извлекаем количество элементов, используя свойство Count, и выполняем итерацию по очереди, используя цикл foreach.

Класс Queue<T> является частью пространства имён `System.Collections.Generic` и предоставляет коллекцию First-In-First-Out (FIFO). Это позволяет вам ставить элементы в очередь в конце, получать доступ к переднему элементу и удалять его, а также эффективно выполнять различные операции, связанные с очередью.

Обратите внимание, что T в Queue<T> представляет параметр типа, что означает, что вы можете использовать класс Queue<T> с различными типами, такими как Queue<int> для хранения целых чисел или Queue<double> для хранения двойных значений.

Ещё одним элементом Extended является Linked list.

Вот пример того, как вы можете использовать базовую реализацию односвязного списка на C#:

“`csharp

using System;

class Node<T>

{

    public T Data { get; set; }

    public Node<T> Next { get; set; }

    public Node(T data)

    {

        Data = data;

        Next = null;

    }

}

class LinkedList<T>

{

    private Node<T> head;

    public void Add(T data)

    {

        Node<T> newNode = new Node<T>(data);

        if (head == null)

        {

            head = newNode;

        }

        else

        {

            Node<T> current = head;

            while (current.Next != null)

            {

                current = current.Next;

            }

            current.Next = newNode;

        }

    }

    public void Print()

    {

        Node<T> current = head;

        while (current != null)

        {

            Console.Write(current.Data + ” “);

            current = current.Next;

        }

        Console.WriteLine();

    }

}

class Program

{

    static void Main()

    {

        LinkedList<int> list = new LinkedList<int>();

        list.Add(10);

        list.Add(20);

        list.Add(30);

        list.Print();

    }

}

“`

В этом примере мы определяем класс `Node<T>` для представления узла в связанном списке. Каждый узел содержит данные типа `T` и ссылку на следующий узел (`Next`). Затем мы определяем класс `LinkedList<T>`, который использует класс `Node<T>` для создания связанного списка и управления им. Класс `LinkedList<T>` имеет методы для добавления узлов (`Add`) и печати списка (`Print`).

В методе `Add` (Добавить) мы создаём новый узел с предоставленными данными и просматриваем список, чтобы найти последний узел. Как только мы достигаем последнего узла, мы устанавливаем его `Next` ссылку на новый узел, фактически добавляя его в конец списка.

В методе `Print` мы выполняем итерацию по связанному списку, начиная с головного узла, и печатаем данные каждого узла.

В методе `Main` мы создаем экземпляр класса `LinkedList<int>`, добавляем несколько целых чисел в список, а затем печатаем список.

Обратите внимание, что это базовая реализация односвязного списка для демонстрационных целей.

На практике вы можете пожелать добавить дополнительные методы для вставки в определенные позиции, удаления узлов, поиска узлов и обработки других операций со списком в зависимости от ваших требований.

Перейдём к рассмотрению ещё одного элемента “Must Have” – Custom.

Конечно! Вот пример пользовательской реализации односвязного списка на C#:

“`csharp

using System;

class LinkedListNode<T>

{

    public T Data { get; set; }

    public LinkedListNode<T> Next { get; set; }

    public LinkedListNode(T data)

    {

        Data = data;

        Next = null;

    }

}

class LinkedList<T>

{

    private LinkedListNode<T> head;

    private LinkedListNode<T> tail;

    public void AddFirst(T data)

    {

        LinkedListNode<T> newNode = new LinkedListNode<T>(data);

        if (head == null)

        {

            head = newNode;

            tail = newNode;

        }

        else

        {

            newNode.Next = head;

            head = newNode;

        }

    }

    public void AddLast(T data)

    {

        LinkedListNode<T> newNode = new LinkedListNode<T>(data);

        if (head == null)

        {

            head = newNode;

            tail = newNode;

        }

        else

        {

            tail.Next = newNode;

            tail = newNode;

        }

    }

    public void Print()

    {

        LinkedListNode<T> current = head;

        while (current != null)

        {

            Console.Write(current.Data + ” “);

            current = current.Next;

        }

        Console.WriteLine();

    }

}

class Program

{

    static void Main()

    {

        LinkedList<int> list = new LinkedList<int>();

        list.AddFirst(10);

        list.AddLast(20);

        list.AddLast(30);

        list.Print();

    }

}

“`

В этой пользовательской реализации у нас есть класс `LinkedListNode<T>`, представляющий узел в связанном списке. Каждый узел имеет свойство `Data` для хранения данных и свойство `Next` для ссылки на следующий узел.

Класс `LinkedList<T>` управляет связанным списком. У него есть ссылки `head` и `tail` для отслеживания первого и последнего узлов соответственно. Метод `addFirst` добавляет новый узел в начало списка, а метод `addLast` добавляет новый узел в конец списка.

Метод `Print` обходит связанный список, начиная с узла `head`, и печатает данные каждого узла.

В методе `Main` мы создаем экземпляр класса `LinkedList<int>`, добавляем несколько целых чисел в список, используя методы `addFirst` и `addLast`, а затем печатаем список.

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

Выражение `T value` является одним из проявлений элемента ‘Custom’.

Выражение `T value` используется для объявления переменной с именем `value` универсального типа `T`. В C# `T` представляет параметр типа, который может быть заменен любым допустимым типом при использовании кода. Это позволяет вам создавать повторно используемый код, который может работать с различными типами.

Вот пример, иллюстрирующий использование `T value`:

“`csharp

class MyClass<T>

{

    public void PrintValue(T value)

    {

        Console.WriteLine(“Value: ” + value);

    }

}

class Program

{

    static void Main()

    {

        MyClass<int> myIntClass = new MyClass<int>();

        myIntClass.PrintValue(42); // Output: Value: 42

        MyClass<string> myStringClass = new MyClass<string>();

        myStringClass.PrintValue(“Hello, world!”); // Output: Value: Hello, world!

    }

}

“`

В этом примере у нас есть общий класс `MyClass<T>`, у которого есть метод `PrintValue`, который принимает параметр типа `T` с именем `value`. Метод просто печатает переданное ему значение.

В методе `Main` мы создаем два экземпляра `MyClass` – `myIntClass` с `int` в качестве аргумента типа и `myStringClass` с `string` в качестве аргумента типа. Мы вызываем метод `PrintValue` в каждом экземпляре и передаем разные значения (`int` и `string`) в качестве аргументов. Код внутри метода `PrintValue` будет выполнен с соответствующими типами на основе предоставленных аргументов типа, что позволяет коду работать с различными типами.

Используя `T value`, вы можете создать универсальный код, который может обрабатывать различные типы без необходимости писать отдельный код для каждого типа. Буква “T” может быть заменена любым допустимым типом при использовании кода, что делает его гибким и пригодным для повторного использования.

Ключевое слово `out` также входит в элемент ‘Custom’.

Ключевое слово `out` в C# используется в качестве модификатора параметра типа в параметрах универсального типа. Это позволяет параметру типа быть ковариантным, что означает, что он может использоваться только как возвращаемый тип, а не как тип параметра в универсальном классе или методе. Модификатор `out` используется для указания на то, что параметр type используется исключительно для целей вывода.

Вот пример, иллюстрирующий использование ключевого слова `out` с обобщениями:

“`csharp

interface IRepository<out T>

{

    T GetById(int id);

}

class UserRepository : IRepository<User>

{

    public User GetById(int id)

    {

        // Retrieve user from the database

        return new User();

    }

}

class Program

{

    static void Main()

    {

        IRepository<User> userRepository = new UserRepository();

        User user = userRepository.GetById(1);

        // Use the retrieved user

    }

}

“`

В этом примере у нас есть интерфейс `IRepository<T>` с параметром универсального типа `T`, измененным на `out`. Интерфейс определяет единственный метод `GetById`, который возвращает экземпляр типа `T` на основе предоставленного идентификатора.

Класс `UserRepository` реализует интерфейс `IRepository<User>`. Он указывает `User` в качестве аргумента типа для `T` и предоставляет реализацию для метода `GetById`.

В методе `Main` мы создаем экземпляр `UserRepository` и присваиваем его переменной типа `IRepository<User>`. Затем мы вызываем метод `GetById` в репозитории, который возвращает объект `User`, который может быть присвоен переменной `user`.

Используя ключевое слово `out` в интерфейсе `IRepository<T>`, мы указываем, что параметр типа `T` может использоваться только как возвращаемый тип, а не как тип параметра в интерфейсе или его реализациях. Это допускает ковариацию, обеспечивая более гибкое и интуитивно понятное использование универсальных типов в сценариях, где параметр type используется исключительно для целей вывода.

Ключевое слово `in` также является элементом ‘Custom’.

Ключевое слово `in` в C# используется в качестве модификатора параметра типа в параметрах универсального типа. Это позволяет параметру типа быть контравариантным, что означает, что он может использоваться только как тип параметра, а не как тип возвращаемого значения в универсальном классе или методе. Модификатор `in` используется для указания на то, что параметр type используется исключительно для целей ввода.

Вот пример, иллюстрирующий использование ключевого слова `in` с обобщениями:

“`csharp

interface IProcessor<in T>

{

    void Process(T item);

}

class Logger : IProcessor<string>

{

    public void Process(string item)

    {

        // Log the provided string

        Console.WriteLine(“Logging: ” + item);

    }

}

class Program

{

    static void Main()

    {

        IProcessor<string> logger = new Logger();

        logger.Process(“An error occurred.”); // Output: Logging: An error occurred.

    }

}

“`

В этом примере у нас есть интерфейс `IProcessor<T>` с параметром общего типа `T`, измененным на `in`. Интерфейс определяет единственный метод `Process`, который принимает экземпляр типа `T` в качестве параметра и выполняет с ним некоторую обработку.

Класс `Logger` реализует интерфейс `IProcessor<string>`. Он указывает `string` в качестве аргумента типа для `T` и предоставляет реализацию для метода `Process`, который регистрирует предоставленную строку.

В методе `Main` мы создаем экземпляр `Logger` и присваиваем его переменной типа `IProcessor<string>`. Затем мы вызываем метод `Process` в регистраторе, передавая строку в качестве аргумента.

Используя ключевое слово `in` в интерфейсе `IProcessor<T>`, мы указываем, что параметр типа `T` может использоваться только как тип параметра, а не как тип возвращаемого значения в интерфейсе или его реализациях. Это допускает контравариантность, обеспечивая более гибкое и интуитивно понятное использование универсальных типов в сценариях, где параметр type используется исключительно для целей ввода.

Ключевое слово `where` тоже является элементом ‘Custom’.

В C# ключевое слово `where` используется в параметрах универсального типа для применения ограничений к типам, которые могут использоваться в качестве аргументов для универсального типа. Это позволяет вам ограничить параметр generic type определенными типами или предъявить определенные требования к аргументам типа.

Вот пример, иллюстрирующий использование ключевого слова `where` с обобщениями:

“`csharp

interface IRepository<T> where T : IEntity

{

    T GetById(int id);

    void Save(T entity);

}

class UserRepository : IRepository<User>

{

    public User GetById(int id)

    {

        // Retrieve user from the database

        return new User();

    }

    public void Save(User entity)

    {

        // Save the user to the database

    }

}

interface IEntity

{

    int Id { get; set; }

}

class User : IEntity

{

    public int Id { get; set; }

    public string Name { get; set; }

}

“`

В этом примере у нас есть интерфейс `IRepository<T>` с параметром универсального типа `T`. Ключевое слово `where` используется для применения ограничения к `T` с помощью `where T : IEntity`. Это означает, что `T` должен реализовывать интерфейс `IEntity`.

Интерфейс определяет два метода, `GetById` и `Save`, которые работают с универсальным типом `T`.

Класс `UserRepository` реализует интерфейс `IRepository<User>`, указывая `User` в качестве аргумента типа для `T`. Класс `User` также реализует интерфейс `IEntity`, который предоставляет свойство `Id`.

Используя ключевое слово `where` с `IRepository<T>`, мы гарантируем, что `T` должен быть типом, реализующим интерфейс `IEntity`. Это ограничение позволяет нам получить доступ к свойству `Id` в методах `GetById` и `Save`.

Применяя ограничения с ключевым словом `where`, вы можете указать требования к типам, которые могут использоваться в качестве универсальных аргументов. Общие ограничения включают интерфейсы, базовые классы, ссылочные типы (`class`), типы значений (`struct`), конструкторы по умолчанию и многое другое. Это помогает обеспечить безопасность типов и обеспечивает более конкретную функциональность в универсальном коде.

Таким образом мы рассмотрели структуру Generics (обобщений)

Схема Дженерики

Spread the love

Добавить комментарий