Далее в классе GenIntfDemo
объявляются три метода увеличения на два для объектов типа int
, double
и ThreeD
. Все эти методы передаются конструктору класса ByTwos
при создании объектов соответствующих типов. Обратите особое внимание на приведенный ниже метод ThreeDPlusTwo()
.
// Определить метод увеличения на два каждого
// последующего значения координат объекта типа ThreeD.
static ThreeD ThreeDPlusTwo(ThreeD v) {
if(v==null) return new ThreeD(0, 0, 0);
else return new ThreeD(v.x + 2, v.y + 2, v.z + 2);
}
В этом методе сначала проверяется, содержит ли переменная экземпляра v пустое значение (null). Если она содержит это значение, то метод возвращает новый объект типа ThreeD
со всеми обнуленными полями координат. Ведь дело в том, что переменной v по умолчанию присваивается значение типа default(Т)
в конструкторе класса ByTwos
. Это значение оказывается по умолчанию нулевым для типов значений и пустым для типов ссылок на объекты. Поэтому если предварительно не был вызван метод SetStart()
, то перед первым увеличением на два переменная v будет содержать пустое значение вместо ссылки на объект. Это означает, что для первого увеличения на два требуется новый объект.
На параметр типа в обобщенном интерфейсе могут накладываться ограничения таким же образом, как и в обобщенном классе. В качестве примера ниже приведен вариант объявления интерфейса ISeries
с ограничением на использование только ссылочных типов.
public interface ISeries
Если реализуется именно такой вариант интерфейса ISeries
, в реализующем его классе следует указать то же самое ограничение на параметр типа Т, как показано ниже.
class ByTwos
В силу ограничения ссылочного типа этот вариант интерфейса ISeries
нельзя применять к типам значений. Поэтому если реализовать его в рассматриваемом здесь примере программы, то допустимым окажется только объявление ByTwos
, но не объявления ByTwos
и ByTwos
.
Сравнение экземпляров параметра типа
Иногда возникает потребность сравнить два экземпляра параметра типа. Допустим, что требуется написать обобщенный метод IsIn()
, возвращающий логическое значение true
, если в массиве содержится некоторое значение. Для этой цели сначала можно попробовать сделать следующее.
// Не годится!
public static bool IsIn
foreach(T v in obs)
if(v == what) // Ошибка! return true;
return false;
}
К сожалению, эта попытка не пройдет. Ведь параметр Т относится к обобщенному типу, и поэтому компилятору не удастся выяснить, как сравнивать два объекта. Требуется ли для этого поразрядное сравнение или же только сравнение отдельных полей? А возможно, сравнение ссылок? Вряд ли компилятор сможет найти ответы на эти вопросы. Правда, из этого положения все же имеется выход.
Для сравнения двух объектов параметра обобщенного типа они должны реализовывать интерфейс IComparable
или IComparable
и/или интерфейс IEquatable
. В обоих вариантах интерфейса IComparable
для этой цели определен метод СоmрагеТо()
, а в интерфейсе IEquatable
— метод Equals()
. Разновидности интерфейса IComparable
предназначены для применения в тех случаях, когда требуется определить относительный порядок следования двух объектов. А интерфейс IEquatable
служит для определения равенства двух объектов. Все эти интерфейсы определены в пространстве имен System
и реализованы во встроенных в C# типах данных, включая int
, string
и double
. Но их нетрудно реализовать и для собственных создаваемых классов. Итак, начнем с обобщенного интерфейса IEquatable
. Интерфейс IEquatable
объявляется следующим образом.
public interface IEquatable
Сравниваемый тип данных передается ему в качестве аргумента типа Т. В этом интерфейсе определяется метод Equals()
, как показано ниже.
bool Equals(Т other)
В этом методе сравниваются вызывающий объект и другой объект, определяемый параметром true
, если оба объекта равны, а иначе — логическое значение false
.