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

на главную

Жанры

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

private string message;

//доступ к свойствам

public string Name

{get {return(name);} set {name = value;}}

public double Salary

{get {return(salary);} set {salary = value;}}

public int Id

{get {return(id);} set {id = value;}}

}//class Person

Класс Person устроен обычным способом: у него несколько перегруженных конструкторов, закрытые поля и процедуры-свойства для доступа к ним. Особо обратить внимание прошу на метод класса ToPerson, сигнатура которого совпадает с сигнатурой класса, определенной введенным ранее делегатом MesToPers.

Посмотрите, как клиент класса может связать этот метод с экземпляром делегата, определенного самим клиентом:

Person man2 = new Person("Владимир");

MesToPers mestopers = new MesToPers(man2.ToPerson);

mestopers("пора работать!");

Обратите внимание, что поскольку метод ToPerson не является статическим методом, то при связывании необходимо передать и объект, вызывающий метод. Более того, переданный объект становится доступным экземпляру делегата. Отсюда сразу же становится ясным, что экземпляры делегата — это не просто указатели на функцию, а более сложно организованные структуры. Они, по крайней мере, содержат пару указателей на метод и на объект, вызвавший метод. Вызываемый метод в своей работе использует как информацию, передаваемую ему через аргументы метода, так и информацию, хранящуюся в полях объекта. В данном примере переданное сообщение "пора работать" присоединится к имени объекта, и результирующая строка будет выдана на печать. В тех случаях, когда метод, связываемый с экземпляром делегата, не использует информацию объекта, этот метод может быть объявлен как статический метод класса. Таким образом, инициализировать экземпляры делегата можно как статическими, так и динамическими методами, связанными с конкретными объектами.

Последние три строки были добавлены в вышеприведенную тестирующую процедуру. Взгляните на результаты ее работы.

Рис. 20.1. Объявление делегатов и создание их экземпляров

Функции высших порядков

Одно из наиболее важных применений делегатов связано с функциями высших порядков. Функцией высшего порядка называется такая функция (метод) класса, у которой один или несколько аргументов принадлежат к функциональному типу. Без этих функций в программировании обойтись довольно трудно. Классическим примером является функция вычисления интеграла, у которой один из аргументов задает подынтегральную функцию. Другим примером может служить функция, сортирующая объекты. Аргументом ее является функция Compare, сравнивающая два объекта. В зависимости оттого, какая функция сравнения будет передана на вход функции сортировки, объекты будут сортироваться по-разному, например, по имени, или по ключу, или по нескольким полям. Вариантов может быть много, и они определяются классом, описывающим сортируемые объекты.

Вычисление интеграла

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

описывающий класс:

public class HighOrderIntegral

{

//delegate

public delegate double SublntegralFun(double x);

public double Evallntegral(double a, double b, double eps,SublntegralFun sif)

{

int n=4;

double I0=0, I1 = I(a, b, n,sif);

for(n=8; n < Math.Pow(2.0,15.0); n*=2)

{

I0 =I1; I1=I(a,b,n,sif);

if(Math.Abs(I1-10)<eps) break;

}

if(Math.Abs(I1–10)< eps)

Console.WriteLine("Требуемая точность достигнута! "+

" eps = {0}, достигнутая точность ={1}, n= {2}",

eps,Math.Abs(11–10), n);

else

Console.WriteLine("Требуемая точность не достигнута! "+

" eps = {0}, достигнутая точность ={1}, n= {2}",

eps,Math.Abs(I1–I0), n);

return(I1);

}

private double I(double a, double b, int n,

SublntegralFun sif)

{

//Вычисляет частную сумму по методу трапеций

double х = a, sum = sif(x)/2, dx = (b-a)/n;

for (int i= 2; i <= n; i++)

{

x += dx; sum += sif (x);

}

x = b; sum += sif(x)/2;

return(sum*dx);

}

}//class HighOrderIntegral

Прокомментирую этот текст:

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

• Метод EvalIntegral — основной метод класса позволяет вычислять определенный интеграл. Этот метод есть функция высшего порядка, поскольку одним из его аргументов является подынтегральная функция, принадлежащая классу SubIntegralFun.

• Для вычисления интеграла применяется классическая схема. Интервал интегрирования разбивается на n частей, и вычисляется частичная сумма по методу трапеций, представляющая приближенное значение интеграла. Затем n удваивается, и вычисляется новая сумма. Если разность двух приближений по модулю меньше заданной точности eps, то вычисление интеграла заканчивается, иначе процесс повторяется в цикле. Цикл завершается либо по достижении заданной точности, либо когда n достигнет некоторого предельного значения (в нашем случае — 215).

• Вычисление частичной суммы интеграла по методу трапеций реализовано закрытой процедурой I.

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

Чтобы продемонстрировать работу с классом HighOrderIntegral, приведу еще класс Functions, где описано несколько функций, удовлетворяющих контракту, который задан классом SubIntegralFun;

class functions

{

//подынтегральные функции

static public double sif1(double x)

{

int k = 1; int b = 2;

return (double)(k*x +b);

}

static public double sif2(double x)

{

double a = 1.0; double b = 2.0; double c= 3.0;

return (double)(a*x*x +b*x +c);

}

}//class functions

А теперь рассмотрим метод класса клиента, выполняющий создание нужных объектов и тестирующий их работу:

public void TestEvalIntegrals

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

Боксер 2: назад в СССР

Гуров Валерий Александрович
2. Боксер
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Боксер 2: назад в СССР

Гром над Тверью

Машуков Тимур
1. Гром над миром
Фантастика:
боевая фантастика
5.89
рейтинг книги
Гром над Тверью

Безымянный раб [Другая редакция]

Зыков Виталий Валерьевич
1. Дорога домой
Фантастика:
боевая фантастика
9.41
рейтинг книги
Безымянный раб [Другая редакция]

Виконт. Книга 2. Обретение силы

Юллем Евгений
2. Псевдоним `Испанец`
Фантастика:
боевая фантастика
попаданцы
рпг
7.10
рейтинг книги
Виконт. Книга 2. Обретение силы

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

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

Чиновникъ Особых поручений

Кулаков Алексей Иванович
6. Александр Агренев
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Чиновникъ Особых поручений

Чужая дочь

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Чужая дочь

Измена. Мой заклятый дракон

Марлин Юлия
Любовные романы:
любовно-фантастические романы
7.50
рейтинг книги
Измена. Мой заклятый дракон

Темный Лекарь 5

Токсик Саша
5. Темный Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Темный Лекарь 5

Барон нарушает правила

Ренгач Евгений
3. Закон сильного
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Барон нарушает правила

Польская партия

Ланцов Михаил Алексеевич
3. Фрунзе
Фантастика:
попаданцы
альтернативная история
5.25
рейтинг книги
Польская партия

Книга пятая: Древний

Злобин Михаил
5. О чем молчат могилы
Фантастика:
фэнтези
городское фэнтези
мистика
7.68
рейтинг книги
Книга пятая: Древний

Наследница Драконов

Суббота Светлана
2. Наследница Драконов
Любовные романы:
современные любовные романы
любовно-фантастические романы
6.81
рейтинг книги
Наследница Драконов

Адепт: Обучение. Каникулы [СИ]

Бубела Олег Николаевич
6. Совсем не герой
Фантастика:
фэнтези
попаданцы
9.15
рейтинг книги
Адепт: Обучение. Каникулы [СИ]