Главная » C# » Ограничения обобщений .NET в Visual C# (Sharp)

0

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

Имеются три типа ограничений: class, new и type. Как правило, ограничение давляется в виде оператора where, как показано в следующем коде:

class Example<DataType> where DataType : new() {

}

Код, выделенный жирным шрифтом, создает впечатление организации наследовия,  где  класс  DataType является  производным  классом  new. Частично  так  оно и есть, поскольку действие создания производного класса является созданием ной функциональности. Но в данном контексте мы не создаем подкласс параметра обобщения .NET, а указываем, что параметр обобщения .NET имеет этот вид фуниональности.

Ограничение type

Ограничения type позволяют ассоциировать тип с параметром обобщения .NET. Например, допустим следующее определение интерфейса:

interface IExample { void Method));

}

Добавление ограничения IExample к параметру обобщения .NET позволяет опредить класс следующим образом:

class ExampleMgr<DataType> where DataType : IExample { DataType _inst;

public ExampleMgr(DataType inst) {

_inst = inst;

}

public void DoSomething() {

_inst.Method();

}

}

В примере ограничение IExample позволяет разработчику вызывать Method. Без этого ограничения обращение к Method вызвало бы ошибку компилятора.

Но  дает  ли  какое-либо  преимущество  такая  возможность  обратиться  к  методу? В конце концов, можно было бы написать код класса ExampieMgr, не прибегая к обобщению .NET, следующим образом:

class ExampieMgr { IExample  _inst;

public ExampieMgr(IExample inst) {

_inst = inst;

}

public void DoSomething() {

_inst.Method();

}

}

В данном случае код с использованием обобщения .NET и код с использованием интерфейса делают одно то же, и применение обобщения .NET не дает никакого преимущества. Но это не всегда так. Рассмотрим следующую модификацию класса

ExampieMgr:

class ExampleMgr<DataType> where DataType : IExample  { DataType _inst;

public ExampieMgr(DataType inst) {

_inst = inst;

}

public void DoSomething() {

_inst.Method();

}

public DataType Inst { get {

return _inst;

}

В данном случае использование обобщения .NET позволяет создание свойства, оащающегося к базовому типу. Если бы был применен код на основе интерфейса, то свойство  inst должно бы  было быть типа  IExample, а чтобы  получить тот же самый эффект, что и с использованием обобщения .NET, необходимо было бы волнять  приведение  типов.  Хотя  необходимость  выполнения  приведения  типов и не означает конец света, это представляет определенные неудобства и не обеспе-

чивает типовой безопасности, т. к. мы не знаем, будет ли приведение успешным до тех пор, пока не выполним код.

В  качестве  ограничений  можно  добавить  несколько  интерфейсов  и  классов,  но в определенных пределах. Эти пределы такие же, как и при создании производного класса или интерфейса:

•    можно создавать подкласс только одного класса;

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

Ограничение new

Назначение ограничения new заключается в том, чтобы позволить создание экземяра типа данных, как показано в следующем примере:

class Example<DataType> where DataType : new() { DataType _value;

public Example() {

_value = new DataType();

}

}

Без ограничения new код, выделенный жирным шрифтом, не скомпилируется. Консуктор, определяемый с ограничением new, не принимает параметров, что может пазаться неудобным.  В конце концов, мы можем захотеть создать экземпляр типа с каким-либо состоянием. В таком случае можно создать ограничения для DataType, после чего создать экземпляр типа, используя инициализаторы объекта. Следующий код показывает пример интерфейса с одним свойством:

interface IBase {

int Value { get; set; }

}

Объединив интерфейс IBase и ключевое слово new в виде ограничений, можно нисать следующий код:

class Example<DataType> where DataType : IBase, new() {

DataType _value;

public Example() {

_value = new DataType { Value = 10 };

}

}

В модифицированном примере жирным шрифтом выделен код, который создает экземпляр типа DataType, после чего использование ограничений позволяет примение инициализатора объекта, который определяет значение value.

Ограничение class

Основным назначением ограничения class является указание, является ли тип обобщения .NET обычным или ссылочным типом. Далее приводится пример типа, который  может  работать  только  со  ссылочными  типами:

class AssumeReferenceType<DataType> where DataType : class { DataType _value;

public AssumeReferenceType(DataType value) {

}

}

Если бы  класс AssumeReferenceType был объявлен типа  int, ТО КОД не скомпилирался бы.  В следующем  коде приводится пример кода,  который  не компилируется:

AssumeReferenceType<IExample> els = new AssumeReferenceType<IExample>(null);

Целью  использования  ограничения  class является  принуждение  стандарта  кодирания,  при  котором  тип  будет  поддерживать только  ссылочные типы.

Источник: Гросс  К. С# 2008:  Пер. с англ. — СПб.:  БХВ-Петербург, 2009. — 576 е.:  ил. — (Самоучитель)

По теме:

  • Комментарии