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

ЖАНРЫ

Интернет-журнал "Домашняя лаборатория", 2007 №9
Шрифт:

{ 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 }; doublet] ar2 = { 3.5, 5.7, 7.9 };

string[] агЗ = { "Мама", "мыла", "Машу", "мылом." };

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, If, del4);

Console.WriteLine("prod= {0}", prod);

}

Обратите

внимание на объявление экземпляра делегата:

Delegate<int>.Del dell;

В момент объявления задается фактический тип, и сигнатура экземпляра становится конкретизированной. Теперь экземпляр можно создать и связать с конкретной функцией. В C# 2.0 это делается проще и естественнее, чем ранее, — непосредственным присваиванием:

del1= this.max2;

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

Покажем, что и сам функциональный тип-делегат можно объявлять с родовыми параметрами. Вот пример такого объявления:

public delegate T FunTwoArg<T> (T a, T b);

Добавим в наш тестовый пример код, демонстрирующий работу с этим делегатом:

FunTwoArg<int> mydel;

myde1 = max 2;

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, дополненный нужными аргументами.

Framework.Net

и универсальность

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

Решение этих задач потребовало введения универсальности не только в язык С#, но и поддержки на уровне каркаса Framework.Net и языка IL, включающем теперь параметризованные типы. Универсальный класс C# не является шаблоном, на основе которого строится конкретизированный класс, компилируемый далее в класс (тип) IL. Компилятору языка C# нет необходимости создавать классы для каждой конкретизации типов универсального класса. Вместо этого происходит компиляция универсального класса C# в параметризованный тип IL. Когда же CLR занимается исполнением управляемого кода, то вся необходимая информация о конкретных типах извлекается из метаданных, сопровождающих объекты.

При этом дублирования кода не происходит и на уровне JIT-компиляторов, которые, однажды сгенерировав код для конкретного типа, сохраняют ссылку на этот участок кода и передают ее, когда такой код понадобится вторично. Это справедливо как для ссылочных, так и значимых типов.

Естественно, что универсальность потребовала введения в библиотеку FCL соответствующих классов, интерфейсов, делегатов и методов классов, обладающих этим свойством.

Так, например, в класс System.Array добавлен ряд универсальных статических методов. Вот один из них:

public static int BinarySearch<T>(Т[] array, T value);

В таблице 22.1 показаны некоторые универсальные классы и интерфейсы библиотеки FCL 2.0 из пространства имен System.Collections.Generic и их аналоги из пространства System.Collections.

23. Отладка и обработка исключительных ситуаций

Корректность и устойчивость. Спецификация системы. Корректность и устойчивость программных систем. Исключительные ситуации. Обработка исключительных ситуаций. Жизненный цикл программной системы. Три закона программотехники. Отладка. Создание надежного кода. Искусство отладки. Отладка и инструментальная среда Visual Studio.Net.

Корректность и устойчивость программных систем

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

В лекции 9 введено строгое понятие корректности метода по отношению к его спецификациям, заданным в виде предусловия и постусловия метода.

Поделиться с друзьями: