Чтение онлайн

на главную - закладки

Жанры

Полное руководство. С# 4.0
Шрифт:

В силу ограничения ссылочного типа этот вариант интерфейса ISeries нельзя применять к типам значений. Поэтому если реализовать его в рассматриваемом здесь примере программы, то допустимым окажется только объявление ByTwos, но не объявления ByTwos и ByTwos. Сравнение экземпляров параметра типа

Иногда возникает потребность сравнить два экземпляра параметра типа. Допу стим, что требуется написать обобщенный метод IsIn, возвращающий логическое значение true, если в массиве содержится некоторое значение. Для этой цели сначала можно попробовать сделать следующее. // Не годится! public static bool IsIn<T>(T what, T[] obs) { foreach(T v in obs) if(v == what) // Ошибка! return true; return false; }

К сожалению, эта попытка не пройдет. Ведь параметр Т относится к обобщенному типу, и поэтому компилятору не удастся выяснить, как сравнивать два объекта. Требу ется ли для этого поразрядное сравнение или же только сравнение

отдельных полей? А возможно, сравнение ссылок? Вряд ли компилятор сможет найти ответы на эти во просы. Правда, из этого положения все же имеется выход.

Для сравнения двух объектов параметра обобщенного типа они должны реализовы вать интерфейс IComparable или IComparable и/или интерфейс IEquatable. В обоих вариантах интерфейса IComparable для этой цели определен метод CompareTo, а в интерфейсе IEquatable — метод Equals. Разновидности интерфейса IComparable предназначены для применения в тех случаях, когда тре буется определить относительный порядок следования двух объектов. А интерфейс IEquatable служит для определения равенства двух объектов. Все эти интерфейсы определены в пространстве имен System и реализованы во встроенных в C# типах дан ных, включая int, string и double. Но их нетрудно реализовать и для собственных создаваемых классов. Итак, начнем с обобщенного интерфейса IEquatable.

Интерфейс IEquatable объявляется следующим образом. public interface IEquatable<T>

Сравниваемый тип данных передается ему в качестве аргумента типа Т. В этом ин терфейсе определяется метод Equals, как показано ниже. bool Equals(Т other)

В этом методе сравниваются взывающий объект и другой объект, определяемый параметром other. В итоге возвращается логическое значение true, если оба объекта равны, а иначе — логическое значение false.

В ходе реализации интерфейса IEquatable обычно требуется также переопре делять методы GetHashCode и Equals(Object), определенные в классе Object, чтобы они оказались совместимыми с конкретной реализацией метода Equals. Ниже приведен пример программы, в которой демонстрируется исправленный вари ант упоминавшегося ранее метода IsIn. // Требуется обобщенный интерфейс IEquatable<T>. public static bool IsIn<T>(T what, T[] obs) where T : IEquatable<T> { foreach(T v in obs) if(v.Equals(what)) // Применяется метод Equals. return true; return false; }

Обратите внимание в приведенном выше примере на применение следующего ограничения. where Т : IEquatable<T>

Это ограничение гарантирует, что только те типы, в которых реализован интерфейс IEquatable, являются действительными аргументами типа для метода IsIn. Вну три этого метода применяется метод Equals, который определяет равенство одного объекта другому.

Для определения относительного порядка следования двух элементов применяется интерфейс IComparable. У этого интерфейса имеются две формы: обобщенная и не обобщенная. Обобщенная форма данного интерфейса обладает преимуществом обе спечения типовой безопасности, и поэтому мы рассмотрим здесь именно ее. Обоб щенный интерфейс IComparable объявляется следующим образом. public interface IComparable<T>

Сравниваемый тип данных передается ему в качестве аргумента типа Т. В этом ин терфейсе определяется метод CompareTo, как показано ниже. int CompareTo(Т other)

В этом методе сравниваются вызывающий объект и другой объект, определяемый параметром other. В итоге возвращается нуль, если вызывающий объект оказывается больше, чем объект other; и отрицательное значение, если вызывающий объект ока зывается меньше, чем объект other.

Для того чтобы воспользоваться методом CompareTo, необходимо указать огра ничение, которое требуется наложить на аргумент типа для реализации обобщенного интерфейса IComparable. А затем достаточно вызвать метод CompareTo, чтобы сравнить два экземпляра параметра типа.

Ниже приведен пример применения обобщенного интерфейса IComparable. В этом примере вызывается метод InRange, возвращающий логическое значение true, если объект оказывается среди элементов отсортированного массива. // Требуется обобщенный интерфейс IComparable<T>. В данном методе // предполагается, что массив отсортирован. Он возвращает логическое // значение true, если значение параметра what оказывается среди элементов // массива, передаваемых параметру obs. public static bool InRange<T>(T what, T[] obs) where T : IComparable<T> { if(what.CompareTo(obs[0]) < 0 || what.CompareTo(obs[obs.Length-1]) > 0) return false; return true; }

В приведенном ниже примере программы демонстрируется применение обоих методов IsIn и InRange на практике. // Продемонстрировать применение обобщенных // интерфейсов IComparable<T> и IEquatable<T>. using System; // Теперь в классе MyClass реализуются обобщенные // интерфейсы IComparable<T> и IEquatable<T>. class MyClass : IComparable<MyClass>, IEquatable<MyClass> { public int Val; public MyClass(int x) { Val = x; } //

Реализовать обобщенный интерфейс IComparable<T>. public int CompareTo(MyClass other) { return Val - other.Val; // Now, no cast is needed. } // Реализовать обобщенный интерфейс IEquatable<T>. public bool Equals(MyClass other) { return Val == other.Val; } // Переопределить метод Equals(Object). public override bool Equals(Object obj) { if(obj is MyClass) return Equals((MyClass) obj); return false; } // Переопределить метод GetHashCode. public override int GetHashCode { return Val.GetHashCode; } } class CompareDemo { // Требуется обобщенный интерфейс IEquatable<T>. public static bool IsIn<T>(T what, T[] obs) where T : IEquatable<T> { foreach(T v in obs) if(v.Equals(what)) // Применяется метод Equals return true; return false; } // Требуется обобщенный интерфейс IComparable<T>. В данном методе // предполагается, что массив отсортирован. Он возвращает логическое // значение true, если значение параметра what оказывается среди элементов // массива, передаваемых параметру obs. public static bool InRange<T>(T what, T[] obs) where T : IComparable<T> { if(what.CompareTo(obs[0]) < 0 || what.CompareTo(ob?[obs.Length-1]) > 0) return false; return true; } // Продемонстрировать операции сравнения. static void Main { // Применить метод IsIn к данным типа int. int[] nums = { 1, 2, 3, 4, 5 }; if(IsIn(2, nums)) Console.WriteLine("Найдено значение 2."); if(IsIn(99, nums)) Console.WriteLine("He подлежит выводу."); // Применить метод IsIn к объектам класса MyClass. MyClass[] mcs = { new MyClass(1), new MyClass(2), new MyClass(3), new MyClass(4) ); if(IsIn(new MyClass), mcs)) Console.WriteLine("Найден объект MyClass)."); if(IsIn(new MyClass(99), mcs)) Console.WriteLine("He подлежит выводу."); // Применить метод InRange к данным типа int. if(InRange(2, nums)) Console.WriteLine("Значение 2 находится в границах массива nums."); if(InRange(1, nums)) Console.WriteLine("Значение 1 находится в границах массива nums."); if(InRange(5, nums)) Console.WriteLine("Значение 5 находится в границах массива nums."); if(!InRange(0, nums)) Console.WriteLine("Значение 0 HE находится в границах массива nums."); if(!InRange(6, nums)) Console.WriteLine("Значение 6 HE находится в границах массива nums."); // Применить метод InRange к объектам класса MyClass. if(InRange(new MyClass(2), mcs)) Console.WriteLine("Объект MyClass(2) находится в границах массива nums."); if(InRange(new MyClass(1), mcs)) Console.WriteLine("Объект MyClass(1) находится " + "в границах массива nums."); if(InRange(new MyClass(4), mcs)) Console.WriteLine("Объект MyClass(4) находится " + "в границах массива nums."); if(!InRange(new MyClass(0), mcs)) Console.WriteLine("Объект MyClass(0) HE " + "находится в границах массива nums."); if (!InRange(new MyClass(5), mcs)) Console.WriteLine("Объект MyClass (5) HE " + "находится в границах массива nums."); } }

Выполнение этой программы приводит к следующему результату. Найдено значение 2. Найден объект MyClass(3). Значение 2 находится в границах массива nums. Значение 1 находится в границах массива nums. Значение 5 находится в границах массива nums. Значение 0 НЕ находится в границах массива nums Значение 6 НЕ находится в границах массива nums Объект MyClass(2) находится в границах массива nums. Объект MyClass(1) находится в границах массива nums. Объект MyClass(4) находится в границах массива nums. Объект MyClass(0) НЕ находится в границах массива nums. Объект MyClass(5) НЕ находится в границах массива nums.

ПРИМЕЧАНИЕ Если параметр типа обозначает ссылку или ограничение на базовый класс, то к экземплярам объектов, определяемых таким параметром типа, можно применять операторы == и !=, хотя они проверяют на равенство только ссылки. А для сравнения значений придется реализовать интер фейс IComparable или же обобщенные интерфейсы IComparable и lEquatable. Иерархии обобщенных классов

Обобщенные классы могут входить в иерархию классов аналогично необобщенным классам. Следовательно, обобщенный класс может действовать как базовый или про изводный класс. Главное отличие между иерархиями обобщенных и необобщенных классов заключается в том, что в первом случае аргументы типа, необходимые обоб щенному базовому классу, должны передаваться всеми производными классами вверх по иерархии аналогично передаче аргументов конструктора. Применение обобщенного базового класса

Ниже приведен простой пример иерархии, в которой используется обобщенный базовый класс. // Простая иерархия обобщенных классов. using System; // Обобщенный базовый класс. class Gen<T> { Т ob; public Gen(T о) { ob = о; } // Возвратить значение переменной ob. public Т GetOb { return ob; } } // Класс, производный от класса Gen. class Gen2<T> : Gen<T> { public Gen2(T o) : base(o) { // ... } } class GenHierDemo { static void Main { Gen2<string> g2 = new Gen2<string>("Привет"); Console.WriteLine(g2.GetOb); } }

Поделиться:
Популярные книги

Вонгозеро

Вагнер Яна
1. Вонгозеро
Детективы:
триллеры
9.19
рейтинг книги
Вонгозеро

Кротовский, может, хватит?

Парсиев Дмитрий
3. РОС: Изнанка Империи
Фантастика:
попаданцы
альтернативная история
аниме
7.50
рейтинг книги
Кротовский, может, хватит?

Сборник коротких эротических рассказов

Коллектив авторов
Любовные романы:
эро литература
love action
7.25
рейтинг книги
Сборник коротких эротических рассказов

Архонт

Прокофьев Роман Юрьевич
5. Стеллар
Фантастика:
боевая фантастика
рпг
7.80
рейтинг книги
Архонт

Медиум

Злобин Михаил
1. О чем молчат могилы
Фантастика:
фэнтези
7.90
рейтинг книги
Медиум

Титан империи 8

Артемов Александр Александрович
8. Титан Империи
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Титан империи 8

Ведьма Вильхельма

Шёпот Светлана
Любовные романы:
любовно-фантастические романы
8.67
рейтинг книги
Ведьма Вильхельма

Волхв

Земляной Андрей Борисович
3. Волшебник
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волхв

Я еще не барон

Дрейк Сириус
1. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я еще не барон

Темный Патриарх Светлого Рода

Лисицин Евгений
1. Темный Патриарх Светлого Рода
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Темный Патриарх Светлого Рода

Пистоль и шпага

Дроздов Анатолий Федорович
2. Штуцер и тесак
Фантастика:
альтернативная история
8.28
рейтинг книги
Пистоль и шпага

Корпулентные достоинства, или Знатный переполох. Дилогия

Цвик Катерина Александровна
Фантастика:
юмористическая фантастика
7.53
рейтинг книги
Корпулентные достоинства, или Знатный переполох. Дилогия

Ученик. Книга 4

Первухин Андрей Евгеньевич
4. Ученик
Фантастика:
фэнтези
5.67
рейтинг книги
Ученик. Книга 4

Часовое имя

Щерба Наталья Васильевна
4. Часодеи
Детские:
детская фантастика
9.56
рейтинг книги
Часовое имя