Особенности сооружения опор в сложных условиях: Сооружение ВЛ в районах с суровыми климатическими и тяжелыми геологическими условиями...
История создания датчика движения: Первый прибор для обнаружения движения был изобретен немецким физиком Генрихом Герцем...
Топ:
Генеалогическое древо Султанов Османской империи: Османские правители, вначале, будучи еще бейлербеями Анатолии, женились на дочерях византийских императоров...
Комплексной системы оценки состояния охраны труда на производственном объекте (КСОТ-П): Цели и задачи Комплексной системы оценки состояния охраны труда и определению факторов рисков по охране труда...
Когда производится ограждение поезда, остановившегося на перегоне: Во всех случаях немедленно должно быть ограждено место препятствия для движения поездов на смежном пути двухпутного...
Интересное:
Наиболее распространенные виды рака: Раковая опухоль — это самостоятельное новообразование, которое может возникнуть и от повышенного давления...
Инженерная защита территорий, зданий и сооружений от опасных геологических процессов: Изучение оползневых явлений, оценка устойчивости склонов и проектирование противооползневых сооружений — актуальнейшие задачи, стоящие перед отечественными...
Берегоукрепление оползневых склонов: На прибрежных склонах основной причиной развития оползневых процессов является подмыв водами рек естественных склонов...
Дисциплины:
2017-10-11 | 199 |
5.00
из
|
Заказать работу |
|
|
До сих пор рассматривалась ситуация родового порождения экземпляров универсального класса. Фактические типы задавались в момент создания экземпляра. Это наглядно показывает преимущества применяемой технологии, поскольку очевидно, что не создается дублирующий код для каждого класса, порожденного универсальным классом. И все-таки остается естественный вопрос: можно ли породить класс из универсального класса путем подстановки фактических параметров, а потом спокойно использовать этот класс обычным образом? Такая вещь возможна. Это можно сделать не совсем обычным путем - не в программном коде, а в предложении using, назначение которого и состоит в выполнении подобных подстановок.
Давайте вернемся к универсальному классу OneLinkStack<T>, введенному в начале этой лекции, и породим на его основе вполне конкретный класс IntStack, заменив формальный параметр T фактическим - int. Для этого достаточно задать следующее предложение using:
using IntStack = Generic.OneLinkStack<int>;Вот тест, в котором создаются несколько объектов этого класса:
public void TestIntStack(){ IntStack stack1 = new IntStack(); IntStack stack2 = new IntStack(); IntStack stack3 = new IntStack(); stack1.put(11); stack1.put(22); int x1 = stack1.item(), x2 = stack1.item(); if ((x1 == x2) && (x1 == 22)) Console.WriteLine("OK!"); stack1.remove(); x2 = stack1.item(); if ((x1!= x2) && (x2 == 11)) Console.WriteLine("OK!"); stack1.remove(); x2 = (stack1.empty())? 77: stack1.item(); if ((x1!= x2) && (x2 == 77)) Console.WriteLine("OK!"); stack2.put(55); stack2.put(66); stack2.remove(); int s = stack2.item(); if (!stack2.empty()) Console.WriteLine(s); stack3.put(333); stack3.put((int)Math.Sqrt(Math.PI)); int res = stack3.item(); stack3.remove(); res += stack3.item(); Console.WriteLine("res= {0}", res);}Все работает заданным образом, можете поверить.
Универсальность и специальные случаи классов
Универсальность - это механизм, воздействующий на все элементы языка. Поэтому он применим ко всем частным случаям классов C#.
|
Универсальные структуры
Так же, как и обычный класс, структура может иметь родовые параметры. Синтаксис объявления, ограниченная универсальность, другие детали универсальности естественным образом распространяются на структуры. Вот типичный пример:
public struct Point<T>{ T x, y;//координаты точки, тип которых задан параметром // другие свойства и методы структуры}Универсальные интерфейсы
Интерфейсы чаще всего следует делать универсальными, предоставляя большую гибкость для позднейших этапов создания системы. Возможно, вы заметили применение в наших примерах универсальных интерфейсов библиотеки FCL - IComparable<T> и других. Введение универсальности, в первую очередь, сказалось на библиотеке FCL - внутренних классов, определяющих поведение системы. В частности, для большинства интерфейсов появились универсальные двойники с параметрами. Если бы в наших примерах мы использовали не универсальный интерфейс, а обычный, то потеряли бы в эффективности, поскольку сравнение объектов потребовало бы создание временных объектов типа object, выполнения операций boxing и unboxing.
Универсальные делегаты
Делегаты также могут иметь родовые параметры. Чаще встречается ситуация, когда делегат объявляется в универсальном классе и использует в своем объявлении параметры универсального класса. Давайте рассмотрим ситуацию с делегатами более подробно. Вот объявление универсального класса, не очень удачно названного Delegate, в котором объявляется функциональный тип - delegate:
class Delegate<T>{ public delegate T Del(T a, T b);}Как видите, тип аргументов и возвращаемого значения в сигнатуре функционального типа определяется классом Delegate.
Добавим в класс функцию высшего порядка FunAr, одним из аргументов которой будет функция типа Del, заданного делегатом. Эта функция будет применяться к элементам массива, передаваемого также функции FunAr. Приведу описание:
public T FunAr(T[] arr, T a0, Del f){ T temp = a0; for(int i =0; i<arr.Length; i++) { temp = f(temp, arr[i]); } return (temp);}Эта универсальная функция с успехом может применяться для вычисления сумм, произведения, минимума и других подобных характеристик массива.
|
Рассмотрим теперь клиентский класс Testing, в котором определен набор функций:
public int max2(int a, int b) { return (a > b)? a: b; }public double min2(double a, double b) { return (a < b)? a: b; }public string sum2(string a, string b) { return a + b; }public float prod2(float a, float b) { return a * b; }Хотя все функции имеют разные типы, все они соответствуют определению класса Del - имеют два аргумента одного типа и возвращают результат того же типа. Посмотрим, как они применяются в тестирующем методе класса Testing:
public void TestFun(){ int[] ar1 = { 3, 5, 7, 9 }; double[] ar2 = { 3.5, 5.7, 7.9 }; string[] ar3 = { "Мама ", "мыла ", "Машу ", "мылом." }; float[] ar4 = { 5f, 7f, 9f, 11f }; Delegate<int> d1 = new Delegate<int>(); Delegate<int>.Del del1; del1= this.max2; int max = d1.FunAr(ar1, ar1[0], del1); Console.WriteLine("max= {0}", max); Delegate<double> d2 = new Delegate<double>(); Delegate<double>.Del del2; del2 = this.min2; double min = d2.FunAr(ar2, ar2[0], del2); Console.WriteLine("min= {0}", min); Delegate<string> d3 = new Delegate<string>(); Delegate<string>.Del del3; del3 = this.sum2; string sum = d3.FunAr(ar3, "", del3); Console.WriteLine("concat= {0}", sum); Delegate<float> d4 = new Delegate<float>(); Delegate<float>.Del del4; del4 = this.prod2; float prod = d4.FunAr(ar4, 1f, del4); Console.WriteLine("prod= {0}", prod);}Обратите внимание на объявление экземпляра делегата:
Delegate<int>.Del del1;В момент объявления задается фактический тип, и сигнатура экземпляра становится конкретизированной. Теперь экземпляр можно создать и связать с конкретной функцией. В C# 2.0 это делается проще и естественнее, чем ранее, - непосредственным присваиванием:
del1= this.max2;При выполнении этого присваивания производятся довольно сложные действия - проверяется соответствие сигнатуры функции в правой части и экземпляра делегата, в случае успеха создается новый экземпляр делегата, который и связывается с функцией.
Покажем, что и сам функциональный тип-делегат можно объявлять с родовыми параметрами. Вот пример такого объявления:
public delegate T FunTwoArg<T>(T a, T b);Добавим в наш тестовый пример код, демонстрирующий работу с этим делегатом:
FunTwoArg<int> mydel; mydel = max2; max = mydel(17, 21); Console.WriteLine("max= {0}", max);Вот как выглядят результаты работы тестового примера:
Рис. 22.7. Результаты работы с универсальными делегатами
Универсальные делегаты с успехом используются при определении событий. В частности, класс EventHandler, применяемый для всех событий, не имеющих собственных аргументов, теперь дополнен универсальным аналогом, определенным следующим образом:
public void delegate EventHandler<T> (object sender, T args) where T:EventArgsЭтот делегат может применяться и для событий с собственными аргументами, поскольку вместо параметра T может быть подставлен конкретный тип - потомок класса EventArgs, дополненный нужными аргументами.
|
|
Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...
История создания датчика движения: Первый прибор для обнаружения движения был изобретен немецким физиком Генрихом Герцем...
Состав сооружений: решетки и песколовки: Решетки – это первое устройство в схеме очистных сооружений. Они представляют...
Археология об основании Рима: Новые раскопки проясняют и такой острый дискуссионный вопрос, как дата самого возникновения Рима...
© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!