where T
:
IComparable
{
if (o1.CompareTo(o2) < 0) return o1;
return o2;
}
Маркер
where
в C# сообщает компилятору, что указанный в
T
тип должен реа-
лизовывать обобщенный интерфейс
IComparable
того же типа (
T
). Благодаря этому
ограничению компилятор разрешает методу вызвать метод
CompareTo
, потому что
последний определен в интерфейсе
IComparable
.
Теперь, когда код ссылается на обобщенный тип или метод, компилятор должен
убедиться, что в коде указан аргумент типа, удовлетворяющий этим ограничениям.
Пример:
private static void CallMin() {
Object o1 = "Jeff", o2 = "Richter";
Object oMin = Min(o1, o2); // Ошибка CS0311
}
324
Глава.12 .Обобщения
При компиляции этого кода появляется сообщение (ошибка CS0311: тип
object
не может использоваться в качестве параметра-типа
'T'
в обобщенном типе или
методе
'SomeType.Min(T,T)'
. Не существует неявного преобразования ссылки
из
'Object'
в
'System.IComparable'
.
Error CS0311: The type 'object' cannot be used as type parameter 'T' in the generic
type or method 'SomeType.Min(T, T)'. There is no implicit
reference conversion from 'object' to 'System.IComparable'.
Компилятор выдает эту ошибку, потому что
System.Object
не реализует ин-
терфейс
IComparable
. На самом деле
System.Object
вообще не реализует
никаких интерфейсов.
Итак, вы примерно представляете, что такое ограничения и как они работают.
Ограничения можно применять к параметрам типа как обобщенных типов, так
и обобщенных методов (как показано в методе
Min
). Среда CLR не поддерживает
перегрузку по именам параметров типа или по именам ограничений. Перегрузка
типов и методов выполняется только по арности. Покажу это на примере:
// Можно определить следующие типы:
internal sealed class AType {}
internal sealed class AType {}
internal sealed class AType {}
// Ошибка: конфликт с типом AType, у которого нет ограничений.
internal sealed class AType where T : IComparable {}
// Ошибка: конфликт с типом AType
internal sealed class AType {}
internal sealed class AnotherType {
// Можно определить следующие методы:
private static void M() {}
private static void M() {}
private static void M() {}
// Ошибка: конфликт с типом M, у которого нет ограничений
private static void M() where T : IComparable {}
// Ошибка: конфликт с типом M.
private static void M() {}
}
При переопределении виртуального обобщенного метода в переопределяющем
методе должно быть задано то же число параметров-типов, а они, в свою очередь,
наследуют ограничения, заданные для них методом базового класса. Собственно,
переопределяемый метод вообще не вправе задавать ограничения для своих па-
раметров-типов, но может переименовывать параметры-типы. Аналогично, при
реализации интерфейсного метода в нем должно задаваться то же число параме-
тров-типов, что и в интерфейсном методе, причем эти параметры-типы наследуют
ограничения, заданные для них методом интерфейса. Следующий пример демон-
стрирует это правило с помощью виртуальных методов:
325
Верификация.и.ограничения
internal class Base {
public virtual void M
()
where T1 : struct
where T2 : class {
}
}
internal sealed class Derived : Base {
public override void M()
where T3 : EventArgs // Ошибка
where T4 : class // Ошибка
{ }
}
При компиляции этого кода появится сообщение об ошибке (ошибка CS0460:
ограничения для методов интерфейсов с переопределением и явной реализацией
наследуются от базового метода и поэтому не могут быть заданы явно):
Error CS0460: Constraints for override and explicit interface implementation
methods are inherited from the base method, so they cannot be
specified directly
Если из метода
M ,
T4>
класса
Derived
убрать две строки
where
, код успешно
компилируется. Заметьте: разрешается переименовывать параметры типа (в этом
примере имя
T1
изменено на
T3
, а
Т2
— на
Т4
), но изменять (и даже задавать) огра-
ничения нельзя.
Теперь поговорим о различных типах ограничений, которые компилятор и CLR
позволяют применять к параметрам типа. К параметру-типу могут применяться
следующие ограничения:
основное
(primary),
дополнительное
(secondary) и/или
ограничение конструктора
(constructor constraint). Речь о них идет в следующих
трех разделах.
Do'stlaringiz bilan baham: