Generics (классы и методы)
Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy — урок 42 из 70.
Обобщения (Generics) позволяют вам писать классы и методы, которые работают с любым типом данных, сохраняя при этом типобезопасность. Вместо того чтобы писать отдельные классы для IntList, StringList и DoubleList, вы пишете один универсальный класс, который обрабатывает их все.
Обобщенный класс использует параметр типа, обычно называемый T, заключенный в угловые скобки:
public class Box<T>
{
private T content;
public void Store(T item) => content = item;
public T Retrieve() => content;
}
// Использование с различными типами
Box<int> intBox = new Box<int>();
intBox.Store(42);
Box<string> stringBox = new Box<string>();
stringBox.Store("Hello");Когда вы создаете Box<int>, компилятор заменяет каждый T на int. Это обеспечивает проверку типов во время компиляции — вы не сможете случайно сохранить строку в боксе int.
Обобщенные методы работают аналогично, позволяя одному методу работать с различными типами:
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
int x = 1, y = 2;
Swap(ref x, ref y); // x=2, y=1Компилятор выводит тип из аргументов, поэтому вам не нужно писать Swap<int> явно. Обобщения являются основой таких коллекций, как List<T> и Dictionary<TKey, TValue>, позволяя создавать переиспользуемый и типобезопасный код.
Задание
ЛегкоДавайте создадим универсальную систему Storage<T>, которая может хранить и управлять элементами любого типа. Вы создадите многоразовый класс-контейнер, демонстрирующий мощь дженериков (generics) — напишите один раз, используйте с целыми числами, строками или любым другим типом!
Вы организуете свой код в двух файлах:
Storage.cs: Создайте универсальный классStorage<T>в пространстве именDataStorage. Ваш контейнер для хранения должен:- Иметь закрытый массив типа
Tдля хранения элементов и свойствоCount, отслеживающее количество сохраненных элементов - Принимать вместимость (capacity) в конструкторе для инициализации внутреннего массива
- Иметь метод
Add(T item), который добавляет элемент, если есть место - Иметь метод
Get(int index), который возвращает элемент по указанному индексу - Иметь метод
GetAll(), который возвращает все сохраненные элементы, объединенные строкой", "
- Иметь закрытый массив типа
Program.cs: В основном файле продемонстрируйте работу вашего универсального класса с двумя разными типами. СоздайтеStorage<int>иStorage<string>, добавьте элементы в каждый из них и покажите, что один и тот же класс бесперебойно работает с обоими типами.
Вы получите четыре входных значения:
- Первое целое число для хранения
- Второе целое число для хранения
- Первая строка для хранения
- Вторая строка для хранения
Создайте хранилище для целых чисел вместимостью 5 и хранилище для строк вместимостью 5. Добавьте два целых числа в целочисленное хранилище, а две строки — в строковое хранилище.
Выведите результат в следующем формате:
Int storage: {GetAll()}
Int count: {Count}
First int: {Get(0)}
String storage: {GetAll()}
String count: {Count}
First string: {Get(0)}Например, если входные данные — 42, 100, Hello и World, вывод должен быть следующим:
Int storage: 42, 100
Int count: 2
First int: 42
String storage: Hello, World
String count: 2
First string: HelloОбратите внимание, как вы один раз написали класс Storage<T>, но он идеально работает как с int, так и со string — в этом и заключается магия дженериков! Компилятор обеспечивает безопасность типов, поэтому вы не сможете случайно добавить строку в хранилище целых чисел.
Шпаргалка
Обобщения (Generics) позволяют создавать классы и методы, которые работают с любым типом данных, сохраняя при этом типобезопасность.
Обобщенный класс использует параметр типа (обычно T), заключенный в угловые скобки:
public class Box<T>
{
private T content;
public void Store(T item) => content = item;
public T Retrieve() => content;
}При создании экземпляра укажите тип, который заменит T:
Box<int> intBox = new Box<int>();
intBox.Store(42);
Box<string> stringBox = new Box<string>();
stringBox.Store("Hello");Обобщенные методы позволяют одному методу работать с различными типами:
public static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
int x = 1, y = 2;
Swap(ref x, ref y); // Compiler infers type from argumentsОбобщения обеспечивают проверку типов во время компиляции и являются основой таких коллекций, как List<T> и Dictionary<TKey, TValue>.
Попробуйте сами
using System;
using DataStorage;
class Program
{
public static void Main(string[] args)
{
// Чтение входных данных
int num1 = Convert.ToInt32(Console.ReadLine());
int num2 = Convert.ToInt32(Console.ReadLine());
string str1 = Console.ReadLine();
string str2 = Console.ReadLine();
// TODO: Создать Storage<int> вместимостью 5
// TODO: Добавить два целых числа в хранилище целых чисел
// TODO: Создать Storage<string> вместимостью 5
// TODO: Добавить две строки в хранилище строк
// TODO: Вывести результат в требуемом формате
// Int storage: {GetAll()}
// Int count: {Count}
// First int: {Get(0)}
// String storage: {GetAll()}
// String count: {Count}
// First string: {Get(0)}
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыПространства имен и директивыВведение в классы и объектыКлючевое слово 'this'Методы и параметрыПоля и свойстваКонструкторыИнициализаторы объектовИтоги — Простой калькулятор4Наследование
Основы синтаксиса наследования (:)Ключевое слово 'base'Ключевые слова Virtual и OverrideЗапечатанные классыБазовый класс 'object'Итоги — Иерархия сотрудников7Продвинутые возможности
Перегрузка операторовИндексаторы (this[])Переопределение ToString()Методы расширенияПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПотокобезопасный SingletonПаттерн FactoryПаттерн Observer (События)Паттерн Strategy13Финальные испытания
Платформа для онлайн-обученияКомпонент игрового персонажаСервис аренды транспорта2Свойства и статические члены
Автоматически реализуемые свойстваСвойства только для чтения и записиСтатические поля и методыСтатические классыЧлены в виде выражений5Полиморфизм и интерфейсы
Полиморфизм: компиляция vs выполнениеИнтерфейс vs абстрактный классМножественные интерфейсыЯвные интерфейсыUpcasting и DowncastingИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция вместо наследованияGenerics (классы и методы)Делегаты и событияАтрибуты и рефлексияIDisposable и оператор usingОсновы Dependency Injection11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Архитектура классов
Экземплярные и статические данныеКлючевые слова 'readonly' и 'const'Опорные поляПовторение — Менеджер банковских счетов6Инкапсуляция
Модификаторы доступаСвойства для инкапсуляцииРеализация скрытия данныхПаттерны неизменяемостиИтоги — Записи студентов9Переменное количество аргументов
Ключевое слово 'params'Необязательные параметрыИменованные аргументыПерегрузка методов