Шрифт:
Интервал:
Закладка:
Console.WriteLine();
Point<int> p5 = default;
Console.WriteLine("p5.ToString()={0}", p5.ToString());
Сопоставление с образцом в обобщениях (нововведение в версии 7.1)
Еще одним обновлением в версии C# 7.1 является возможность использования сопоставления с образцом в обобщениях. Взгляните на приведенный далее метод, проверяющий экземпляр Point на предмет типа данных, на котором он основан (вероятно, неполный, но достаточный для того, чтобы продемонстрировать концепцию):
static void PatternMatching<T>(Point<T> p)
{
switch (p)
{
case Point<string> pString:
Console.WriteLine("Point is based on strings");
return;
case Point<int> pInt:
Console.WriteLine("Point is based on ints");
return;
}
}
Для использования кода сопоставления с образцом модифицируйте операторы верхнего уровня следующим образом:
Point<string> p4 = default;
Point<int> p5 = default;
<b>PatternMatching(p4);</b>
<b>PatternMatching(p5); </b>
Ограничение параметров типа
Как объяснялось в настоящей главе, любой обобщенный элемент имеет, по крайней мере, один параметр типа, который необходимо указывать во время взаимодействия с данным обобщенным типом или его членом. Уже одно это обстоятельство позволяет строить код, безопасный в отношении типов; тем не менее, вы также можете применять ключевое слово where для определения особых требований к отдельному параметру типа.
С помощью ключевого слова where можно добавлять набор ограничений к конкретному параметру типа, которые компилятор C# проверит на этапе компиляции. В частности, параметр типа можно ограничить, как описано в табл. 10.8.
Возможно, применять ключевое слово where в проектах C# вам никогда и не придется, если только не требуется строить какие-то исключительно безопасные в отношении типов специальные коллекции. Невзирая на сказанное, в следующих нескольких примерах (частичного) кода демонстрируется работа с ключевым словом where.
Примеры использования ключевого слова where
Начнем с предположения о том, что создан специальный обобщенный класс, и необходимо гарантировать наличие в параметре типа стандартного конструктора. Это может быть полезно, когда специальный обобщенный класс должен создавать экземпляры типа Т, потому что стандартный конструктор является единственным конструктором, потенциально общим для всех типов. Кроме того, подобное ограничение Т позволяет получить проверку на этапе компиляции; если Т — ссылочный тип, то программист будет помнить о повторном определении стандартного конструктора в объявлении класса (как вам уже известно, в случае определения собственного конструктора класса стандартный конструктор из него удаляется).
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})// Класс MyGenericClass является производным от object, в то время как
// содержащиеся в нем элементы должны иметь стандартный конструктор.
public class MyGenericClass<T> where T : new()
{
...
}
Обратите внимание, что конструкция where указывает параметр типа, подлежащий ограничению, за которым следует операция двоеточия. После операции двоеточия перечисляются все возможные ограничения (в данном случае — стандартный конструктор). Вот еще один пример:
// Класс MyGenericClass является производным от object, в то время как
// содержащиеся в нем элементы должны относиться к классу, реализующему
// интерфейс IDrawable, и поддерживать стандартный конструктор.
public class MyGenericClass<T> where T : class, IDrawable, new()
{
...
}
Здесь к типу T предъявляются три требования. Во-первых, он должен быть ссылочным типом (не структурой), как помечено лексемой class. Во-вторых, Т должен реализовывать интерфейс IDrawable. В-третьих, тип Т также должен иметь стандартный конструктор. Множество ограничений перечисляются в виде списка с разделителями-запятыми, но имейте в виду, что ограничение new() должно указываться последним! Таким образом, представленный далее код не скомпилируется:
// Ошибка! Ограничение new() должно быть последним в списке!
public class MyGenericClass<T> where T : new(), class, IDrawable
{
...
}
При создании класса обобщенной коллекции с несколькими параметрами типа можно указывать уникальный набор ограничений для каждого параметра, применяя отдельные конструкции where:
// Тип <К> должен расширять SomeBaseClass и иметь стандартный конструктор,
// в то время как тип <Т> должен быть структурой и реализовывать
// обобщенный интерфейс IComparable.
public class MyGenericClass<K, T> where K : SomeBaseClass, new()
where T : struct, IComparable<T>
{
...
- Понимание SQL - Мартин Грубер - Базы данных