Ограничения в обобщенных методах и делегатах. Примеры. Применение ограничений для нескольких типов
Содержание
- 1. Применение ограничений в обобщенных методах. Пример
- 2. Применение ограничений в обобщенных делегатах. Пример
- 3. Синтаксис объявления ограничения для нескольких типов T1, T2, …, TN. Объявление ограничения в классе
- 4. Синтаксис объявления обобщенного интерфейса, который получает параметрами типы T1, T2, …, TN
- 5. Синтаксис объявления обобщенной структуры, которая содержит ограничения для типов T1, T2, …, TN
- 6. Синтаксис объявления ограничения в обобщенном методе, который получает параметрам несколько типов содержащих ограничения. Пример
- 7. Синтаксис объявления ограничений на несколько типов в обобщенном делегате
- 8. Пример класса, получающего параметрами типы T1, T2 на которые накладываются ограничения
- Связанные темы
Поиск на други ресурсах:
1. Применение ограничений в обобщенных методах. Пример
Ограничения могут применяться к отдельным методам классов. В этом случае синтаксис объявления ограничения в методе класса следующий
return_type MethodName<T>(parameters) where T : bounds { // ... }
здесь
- return_type — тип, возвращаемый методом. Этот тип также может быть типом T;
- T — тип, которые получает метод в качестве параметра;
- MethodName(parameters) — имя метода с перечнем параметров;
- bounds — ограничения, накладываемые на тип T. Ограничение может быть одним из перечня struct, class, BaseClass, Interface, new().
Пример. В примере объявляется два класса:
- класс MyClass, в котором объявляется обобщенный метод Print<T>();
- класс A. Ссылка на этот класс будет передаваться в метод Print<T>().
Фрагмент кода классов и метода следующий
class MyClass { // Обрабатываются только типы-ссылки public void Print<T>(T obj) where T : class { Console.WriteLine("obj: " + obj.ToString()); } } // Некоторый класс class A { // ... } ...
Как видно из вышеприведенного кода, в классе MyClass метод Print<T>() получает параметром тип T, на который накладывается ограничение
where T : class
Это означает, что в качестве типа T могут быть использованы только типы ссылки.
В функции main() (или других методах) метод Print<T>() может быть использован следующим образом
... // 1. Объявить экземпляр класса MyClass MyClass obj1 = new MyClass(); // 2. Объявить экземпляр класса A A obj2 = new A(); // obj2 - ссылочного типа // 3. Вызвать метод Print<T> и передать ему ссылочный тип (obj2) obj1.Print<A>(obj2); // работает! ...
Если попытаться использовать тип-значение, то возникнет ошибка на этапе компиляции
// Вызвать метод Print<T> и передать ему тип-значение (val) int val = 38; // val - тип-значение (значимый тип) obj1.Print<int>(val); // здесь ошибка компиляции
⇑
2. Применение ограничений в обобщенных делегатах. Пример
Ограничения могут применяться к делегатам. Общая форма применения ограничения к делегату, который получает параметром тип T, выглядит следующим образом
delegate return_type DelegateName<T>(parameters) where T : bounds;
здесь
- DelegateName — имя делегата, который возвращает тип return_type и получает параметром список parameters;
- bounds — перечень ограничений, которые накладываются на тип T.
Пример.
Объявляется делегат Oper3, что получает тип T в качестве параметра типа. Тип T ограничивается структурными типами (struct).
Также объявляется структура Operations, которая содержит три статических метода:
- Max3() — определяет максимальное значение между тремя числами типа double;
- Min3() — определяет минимальное значение между тремя числами типа double;
- Avg3() — определяет среднее значение между тремя числами типа double.
// Обобщенный делегат, в котором тип T // должен быть структурного типа delegate T Oper3<T>(T a, T b, T c) where T : struct; // Структура, содержащая статические методы оперирования данными struct Operation { // Максимальное между тремя числами public static double Max3(double a, double b, double c) { double max = a; if (max < b) max = b; if (max < c) max = c; return max; } // Среднее между тремя числами public static double Avg3(double a, double b, double c) { if (((a > b) && (a < c)) || ((a > c) && (a < b))) return a; if (((b > a) && (b < c)) || ((b > c) && (b < a))) return b; return c; } // Минимальное между тремя числами public static double Min3(double a, double b, double c) { double min = a; if (min > b) min = b; if (min > c) min = c; return min; } }
В другой функции (например, функции main()) делегат Oper3 может быть использован следующим образом
... // Объявить ссылку на обобщенный делегат Oper3<double> op; // Присвоить ссылке адрес метода Operation.Max() op = Operation.Max3; // Вызвать метод Operation.Max() через делегат double max = op(2.8, 3.5, 1.4); Console.WriteLine("max = {0}", max); // max = 3.5 // Вызвать метод Avg() через делегат op op = Operation.Avg3; double avg = op(2.8, 3.5, 1.4); Console.WriteLine("avg = {0}", avg); // avg = 2.8 ...
⇑
3. Синтаксис объявления ограничения для нескольких типов T1, T2, …, TN. Объявление ограничения в классе
Обобщенный элемент программы (класс, структура, интерфейс, метод, делегат) может получать в качестве параметров несколько типов T1, T2, …, TN.
Синтаксис объявления класса, в котором несколько параметров типа получают следующие ограничения:
class ClassName<T1, T2, ..., TN> where T1 : bounds1 where T2 : bounds2 ... where TN : boundsN { // ... }
здесь
- T1, T2, TN — параметры типов, которыми оперирует класс;
- bounds1, bounds2, boundsN — соответственно ограничения на типы T1, T2, TN.
⇑
4. Синтаксис объявления обобщенного интерфейса, который получает параметрами типы T1, T2, …, TN
Синтаксис объявления интерфейса, который использует несколько типов, следующий
interface InterfaceName<T1, T2, ..., TN> where T1 : bounds1 where T2 : bounds2 ... where TN : boundsN { // ... }
Класс, реализующий данный интерфейс должен учитывать ограничение для каждого типа. Иначе возникнет ошибка компиляции.
⇑
5. Синтаксис объявления обобщенной структуры, которая содержит ограничения для типов T1, T2, …, TN
Синтаксис объявления структуры, содержащей ограничения для нескольких типов, выглядит следующим образом
struct StructName<T1, T2, ..., TN> where T1 : bounds1 where T2 : bounds2 ... where TN : boundsN { // ... }
⇑
6. Синтаксис объявления ограничения в обобщенном методе, который получает параметрам несколько типов содержащих ограничения. Пример
Если в некотором элементе программы (класс, структура, интерфейс) объявляется обобщенный метод, который получает параметрами несколько типов T1, T2, …, TN, то для каждого типа могут накладываться ограничения. В этом случае синтаксис объявления метода следующий:
return_type MethodName<T1, T2, ..., TN>(parameters) where T1 : bounds1 where T2 : bounds2 ... where TN : boundsN { // ... }
здесь
- return_type – тип, возвращаемый методом;
- T1, T2, TN – типы-параметры;
- bounds1, bounds2, boundsN – соответственно ограничения на типы T1, T2, TN;
- parameters – параметры, которые получает метод.
Пример. Объявляется класс с именем SomeClass, который содержит обобщенный метод Method<T1, T2, T3>, получающий три параметра типа. Для первого параметра T1 устанавливается ограничение struct. Для второго параметра T2 устанавливается ограничение class. Для параметра T3 устанавливается ограничение базового класса FileStream и ограничения на наличие конструктора без параметров.
// Класс, в котором объявлен метод оперирующий тремя типами class SomeClass { public void Method<T1, T2, T3>() where T1 : struct where T2 : class where T3 : System.IO.FileStream, new() { // ... } }
⇑
7. Синтаксис объявления ограничений на несколько типов в обобщенном делегате
Если нужно чтобы делегат оперировал несколькими типами T1, T2, …, TN, на которые накладываются ограничения, то синтаксис объявления такого делегата следующий
delegate return_type DelegateName<T1, T2, ..., TN>(parameters) where T1 : bounds1 where T2 : bounds2 ... where TN : boundsN;
здесь
- return_type – тип, возвращаемый делегатом;
- T1, T2, TN – типы-параметры;
- bounds1, bounds2, boundsN – соответственно ограничения на типы T1, T2, TN;
- parameters – параметры, которые получает делегат.
⇑
8. Пример класса, получающего параметрами типы T1, T2 на которые накладываются ограничения
В примере приведен фрагмент программы, в котором объявляется класс, содержащий обобщенный метод. Этот метод получает параметрами два типа T1, T2. На каждый из типов накладывается ограничение типа struct. Это ограничение обязывает указывать параметрами типа только типы-значения (int, double, Int32, Single, bool, Boolean, …).
using System; namespace ConsoleApp19 { // Применение ограничений в обобщенных методах // Класс, содержащий обобщенный метод Print2<T1, T2>, // который работает только с типами-значениями class MyClass { // Метод Print2() получает два параметра типа T1, T2. // Метод выводит информацию об этих типах public void Print2<T1, T2>(T1 obj1, T2 obj2) where T1 : struct where T2 : struct { // Получить информацию об экземплярах obj1, obj2 Type tp1 = obj1.GetType(); Type tp2 = obj2.GetType(); Console.WriteLine("obj1.Name = " + tp1.Name); Console.WriteLine("obj1.IsClass = {0}", tp1.IsClass); Console.WriteLine("obj2.Name = " + tp2.Name); Console.WriteLine("obj2.IsClass = {0}", tp2.IsClass); } } class Program { static void Main(string[] args) { // Использовать метод Print2<T1, T2>() класса MyClass // 1. Создать экземпляр класса MyClass() MyClass obj1 = new MyClass(); // 2. Вызвать метод Print2<T1, T2>) экземпляра obj1 obj1.Print2<int, double>(28, 3.88); Console.WriteLine("Ok!"); Console.ReadKey(); } } }
Результат выполнения программы
obj1.Name = Int32 obj1.IsClass = False obj2.Name = Double obj2.IsClass = False Ok!
Если в строке вызова метода Print2<T1, T2> вместо типа-значения указать ссылочный тип, например,
// 2. Указать ссылочный тип String s1 = "Hello world!"; System.Text.StringBuilder s2 = new System.Text.StringBuilder(); // Этот код содержит ошибку obj1.Print2<String, System.Text.StringBuilder>(s1, s2); // ошибка компиляции
то компилятор выдаст ошибку. В этом случае сработают ограничения
where T1 : struct where T2 : struct
в объявлении метода Print2().
⇑
Связанные темы
- Обобщения. Основные понятия. Обобщенные классы и структуры
- Ограниченные типы. Общие понятия. Ограничения ссылочного и структурного типов
- Ограничения на конструктор, базовый класс и интерфейс
⇑