Конечно, мы можем сами обработать исключение, но тогда придется каждую попытку обращения к коллекции обрамлять предохраняющим блоком кодов. Например:
try
{
goods[0] = new Object();
}
catch (ArgumentOutOfRangeException e)
{
Console.WriteLine ("\nI got the exception:\n" + e.Message);
}
Не поленитесь и проверьте работу этого фрагмента (при пустой коллекции). Приятным моментом здесь является та обстоятельность, с которой объект e выводит причину ошибки. Несмотря на это приятное открытие, подобный подход к разработке программ способен привести в уныние любого программиста. Хотя, за всех не скажешь.
Теперь посмотрим, как в аналогичной ситуации поведет себя индексатор. Для этого вновь измените тело функции Main. В ней мы сначала поработаем со списком без явных ошибок, а затем специально обратимся к нему с недопустимыми значениями индекса.
static void Main()
{
object[] goods = { "Bike", "Wife", "Summer House" };
Man alex = new Man ("Alex Black", 56, goods); // Создадим богатого человека
object o = alex[0]; // Проверим поведение аксессора get
Console.WriteLine(o);
Console.WriteLine("Alex has: {0}, {1}, {2}", alex[0], alex[1], alex[2]);
alex[0] = "New Bike"; // Проверим поведение аксессора set
Console.WriteLine (alex[0]); // и снова get
}
Для тех, кто не имеет под рукой компьютера с установленной на нем лицензионной версией студии, сообщим, что после запуска приложения в консольном окне события будут развиваться по такому сценарию:
alex[0] = Bike
Alex has: Bike, Wife, Summer House
alex[0] = New Bike
Теперь проверим поведение индексатора в случае некорректного обращения с индексом. Добавьте в конец функции Main такие строки.
//==== Проверим поведение средств защиты
Console.Write (alex [-1]);// get
alex [2048] = o; // set
Хорошо то, что приложение не прерывается и реагирует на ошибки вполне адекватным образом. В окне вы видите ту реакцию, которая было заложена нами при создании индексатора.
get: wrong id = -1
set: wrong id = 2048
В заключение обзора возможностей индексатора, отметим, что применение индексатора, например, для класса «многоугольник» было бы более естественным, чем для объектов класса Man. С помощью индексатора мы могли бы простым образом опрашивать или устанавливать координаты произвольной вершины многоугольника.
Синтаксис индексатора напоминает синтаксис свойств, но запомните. Свойство может быть как обычным членом класса, так и статическим. Индексатор же статическим быть не может.
Делегаты имеют известный нам аналог в языке С++. Им является указатель на функцию. Вспомним, как это делается. Имя функции в C++ — это адрес ее начала (адрес точки входа). При работе с указателем на функцию мы сначала должны его объявить. Это можно сделать так:
double (*pTrig) (double) = sin;
cout << "sin(1.57) = " << pTrig(1.57)<<"\n\n";
Указатель pTrig объявлен, инициализирован адресом функции sin и использован для ее вызова pTrig(1.57). Далее этот же указатель может быть использован для вызова другой функции, но с той же сигнатурой. Например:
pTrig = tan;
cout << "tan (0.78) = " << pTrig (0.78)<<"\n\n";
Если мы имеем свою собственную функцию Sum с сигнатурой, соответствующей указателю, то и ее можно вызвать с помощью pTrig, например:
double Sum (double eps)
{
double sum = 1.;
for (int n=2, s=1; fabs(1./n) > eps; n++, s=-s)
sum += double(s)/n;
return sum;
}
Иллюстрируем все вызовы в одном месте.
void main()
{
double (*pTrig) (double) = sin;
cout << "sin (1.57) = " << pTrig(1.57)<<"\n\n";
pTrig = tan;
cout << "tan (0.78) = " << pTrig (0.78)<<"\n\n";
pTrig = Sum;
cout << "Sum (1e-5) = " << pTrig (1e-5)<<"\n\n";
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.