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

на главную

Жанры

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

Вот к какому результату приводит выполнение этого кода. Переменная x.obj имеет пустое значение <null>. Переменная у.obj имеет значение 0. Обобщенные структуры

В C# разрешается создавать обобщенные структуры. Синтаксис для них такой же, как и для обобщенных классов. В качестве примера ниже приведена программа, в ко торой создается обобщенная структура XY для хранения координат X, Y. // Продемонстрировать применение обобщенной структуры. using System; // Эта структура является обобщенной. struct XY<T> { Т х; Т у; public XY(Т а, Т b) { х = а; У = b; } public Т X { get { return х; } set { х = value; } } public T Y { get { return y; } set { у = value; } } } class StructTest { static void Main { XY<int> xy = new XY<int>(10, 20); XY<double> xy2 = new XY<double>(88.0, 99.0); Console.WriteLine(xy.X + ", " + xy.Y); Console.WriteLine(xy2.X + ", " + xy2.Y); } }

При

выполнении этой программы получается следующий результат. 10, 20 88, 99

Как и на обобщенные классы, на обобщенные структуры могут накладываться огра ничения. Например, на аргументы типа в приведенном ниже варианте структуры XY накладывается ограничение типа значения. struct XY<T> where Т : struct { // ... Создание обобщенного метода

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

Рассмотрим для начала простой пример. В приведенной ниже программе объяв ляется необобщенный класс ArrayUtils, а в нем — статический обобщенный метод CopyInsert. Этот метод копирует содержимое одного массива в другой, вводя по ходу дела новый элемент в указанном месте. Метод CopyInsert можно использо вать вместе с массивами любого типа. // Продемонстрировать применение обобщенного метода. using System; // Класс обработки массивов. Этот класс не является обобщенным. class ArrayUtils { // Копировать массив, вводя по ходу дела новый элемент. // Этот метод является обобщенным. public static bool CopyInsert<T> (Т e, uint idx, T[] src, T[] target) { // Проверить, насколько велик массив. if(target.Length < src.Length+1) return false; // Скопировать содержимое массива src в целевой массив, // попутно введя значение е по индексу idx. for(int i=0, j=0; i < src.Length; i++, j++) { if(i == idx) { target[j] = e; j++; } target[j] = src[i]; } return true; } } class GenMethDemo { static void Main { int[] nums = { 1, 2, 3 }; int[] nums2 = new int[4]; // Вывести содержимое массива nums. Console.Write("Содержимое массива nums: "); foreach(int x in nums) Console.Write(х + " "); Console.WriteLine; // Обработать массив типа int. ArrayUtils.Copylnsert(99, 2, nums, nums2); // Вывести содержимое массива nums2. Console.Write("Содержимое массива nums2: "); foreach(int x in nums2) Console.Write(x + " "); Console.WriteLine; //А теперь обработать массив строк, используя метод copyInsert. string[] strs = {"Обобщения", "весьма", "эффективны."}; string[] strs2 = new string[4]; // Вывести содержимое массива strs. Console.Write("Содержимое массива strs: "); foreach(string s in strs) Console.Write(s + " "); Console.WriteLine; // Ввести элемент в массив строк. ArrayUtils.Copylnsert("в С#", 1, strs, strs2); // Вывести содержимое массива strs2. Console.Write("Содержимое массива strs2: "); foreach(string s in strs2) Console.Write(s + " "); Console.WriteLine; // Этот вызов недопустим, поскольку первый аргумент // относится к типу double, а третий и четвертый // аргументы обозначают элементы массивов типа int. // ArrayUtils.Copylnsert(0.01, 2, nums, nums2); } }

Вот к какому результату приводит выполнение этой программы. Содержимое массива nums: 1 2 3 Содержимое массива nums2: 1 2 99 3 Содержимое массива strs: Обобщения весьма эффективны. Содержимое массива strs2: Обобщения в C# весьма эффективны.

Внимательно проанализируем метод CopyInsert. Прежде всего обратите вни мание на объявление этого метода в следующей строке кода. public static bool CopyInsert<T>(Т e, uint idx, T[] src, T[] target) {

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

Далее обратите внимание на то, что метод CopyInsert вызывается в методе Main с помощью обычного синтаксиса и без указания аргументов типа. Дело в том, что типы аргументов различаются автоматически, а тип Т соответственно подстраи вается. Этот процесс называется выводимостью типов. Например, в первом вызове дан ного метода ArrayUtils.CopyInsert(99, 2, nums, nums2);

тип T становится типом int, поскольку числовое значение 99 и элементы массивов nums и nums2 относятся к типу int. А во втором вызове данного метода используются строковые типы, и поэтому тип Т заменяется типом string.

А теперь обратите внимание на приведенную ниже закомментированную строку кода. // ArrayUtils.CopyInsert(0.01, 2, nums, nums2);

Если удалить символы комментария в начале этой строки кода и затем попытаться перекомпилировать программу, то будет получено сообщение об ошибке. Дело в том, что первый аргумент в данном вызове метода CopyInsert относится к типу double, а третий и четвертый аргументы обозначают элементы массивов nums и nums2 типа int. Но все эти аргументы типа должны заменить один и тот же параметр типа Т, а это приведет к несоответствию типов и, как следствие, к ошибке во время компиля ции. Подобная возможность соблюдать типовую безопасность относится к одним из самых главных преимуществ обобщенных методов.

Синтаксис объявления метода CopyInsert может быть обобщен. Ниже приве дена общая форма объявления обобщенного метода. возвращаемый_тип имя_метода<список_параметров_типа>(список_параметров) { // ...

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

В большинстве случаев неявной выводимости типов оказывается достаточно для вы зова обобщенного метода, тем не менее аргументы типа могут быть указаны явным об разом. Для этого достаточно указать аргументы типа после имени метода при его вы зове. В качестве примера ниже приведена строка кода, в которой метод CopyInsert вызывается с явно указываемым аргументом типа string. ArrayUtils.CopyInsert<string>("В С#", 1, strs, strs2);

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

На аргументы обобщенного метода можно наложить ограничения, указав их после списка параметров. В качестве примера ниже приведен вариант метода CopyInsert для обработки данных только ссылочных типов. public static bool CopyInsert<T>(Т e, uint idx, T[] src, T[] target) where T : class {

Если попробовать применить этот вариант в предыдущем примере программы об работки массивов, то приведенный ниже вызов метода CopyInsert не будет ском пилирован, поскольку int является типом значения, а не ссылочным типом. // Теперь неправильно, поскольку параметр Т должен быть ссылочного типа! ArrayUtils.Copylnsert(99, 2, nums, nums2); // Теперь недопустимо! Обобщенные делегаты

Как и методы, делегаты также могут быть обобщенными. Ниже приведена общая форма объявления обобщенного делегата. delegate возврашдемый_тип имя_делегата<список_параметров_типа>(список_аргументов);

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

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

Бездомыш. Предземье

Рымин Андрей Олегович
3. К Вершине
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Бездомыш. Предземье

Фиктивный брак

Завгородняя Анна Александровна
Фантастика:
фэнтези
6.71
рейтинг книги
Фиктивный брак

Правила Барби

Аллен Селина
4. Элита Нью-Йорка
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Правила Барби

Чайлдфри

Тоцка Тала
Любовные романы:
современные любовные романы
6.51
рейтинг книги
Чайлдфри

Купеческая дочь замуж не желает

Шах Ольга
Фантастика:
фэнтези
6.89
рейтинг книги
Купеческая дочь замуж не желает

Идеальный мир для Социопата 13

Сапфир Олег
13. Социопат
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Идеальный мир для Социопата 13

Чемпион

Демиров Леонид
3. Мания крафта
Фантастика:
фэнтези
рпг
5.38
рейтинг книги
Чемпион

Курсант: Назад в СССР 10

Дамиров Рафаэль
10. Курсант
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Курсант: Назад в СССР 10

Черный Маг Императора 4

Герда Александр
4. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 4

Мастер 3

Чащин Валерий
3. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер 3

Кодекс Охотника. Книга XXV

Винокуров Юрий
25. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
6.25
рейтинг книги
Кодекс Охотника. Книга XXV

Неудержимый. Книга XI

Боярский Андрей
11. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Неудержимый. Книга XI

Рядовой. Назад в СССР. Книга 1

Гаусс Максим
1. Второй шанс
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Рядовой. Назад в СССР. Книга 1

Черный Маг Императора 9

Герда Александр
9. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 9