40957

Пример использования делегата

Лекция

Информатика, кибернетика и программирование

Сортируемый класс Employee описывает данные о сотрудниках: код фамилия имя дата приема на работу заработная плата. Это реализуется определением в коде программы делегата: delegte bool CompreOpobject lhs object rhs; Сигнатуру метода сортировки Sort определим следующим образом: sttic public void Sortobject[] sortrry CompreOp gtMethod Параметр sortrry задает массив сортируемых объектов в рассматриваемом примере массив экземпляров класса Employee а параметр gtMethod метод принимающий два параметра и возвращающий true если...

Русский

2013-10-22

112 KB

5 чел.

PAGE  5

Тема 4

Делегаты

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

Перед использованием в программе делегат необходимо объявить при помощи ключевого слова delegate.

Синтаксис объявления делегата:

[модификатор_уровня_доступа] delegate возвращаемый_тип имя_класса_делегата([тип_параметра имя_параметра
[, . . .]]);

Элементы синтаксиса следующие:

модификатор_уровня_доступа – уровень доступа к объявленному делегату, который может задаваться ключевыми словами public, private, protected ;

возвращаемый_тип – тип или класс значения, возвращаемого делегатом;

имя_класса_делегата – имя, назначенное классу делегата;

тип_параметра – тип или класс параметра, передаваемого деленгату;

имя_параметра –  имя параметра, передаваемого делегату.

Пример объявления делегата:

delegate void FirstDelegate(string s);

Пояснение: объявлен делегат с именем FirstDelegate. Экземпляр делегата может ссылаться на метод, принимающий один параметр типа string и возвращающий тип void.

Delegate int SecondDelegate();

Пояснение: объявлен делегат с именем SecondDelegate. Экземпляр делегата может ссылаться на метод, не принимающий параметров и возвращающий значение типа int.

При объявлении делегата декларируется полная сигнатура метода, который он может представлять. Делегат можно объявить внутри какого-то класса, вне любого класса или в пространстве имен объекта высшего уровня. К делегату можно применять любые модификаторы доступа: public, private, protected. 

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

Пример использования делегата. Создадим класс Calculation  с двумя статическими методами: метод Square вычисляет квадрат числа х , а метод Add – удвоение значения числа х. Код класса приведен на рис.1.

public class Calculation

{

   public static double Square(double x)

   { return x * x; }

   public static double Add(double x)

   { return x + x; }

}

Рисунок 1

В классе Program (рис.2) объявим класс делегата DelegateCalculate , который возвращает значение типа double и принимает один параметр типа double. 

class Program

{

   delegate double DelegateCalculate(double x);

   static void Main(string[] args)

   {

       double par = 25;

       DelegateCalculate delCalculate = new
       
DelegateCalculate(Calculation.Square);

       double sdr = delCalculate(par);

       delCalculate = new DelegateCalculate(Calculation.Add);

       double add = delCalculate(par);

       Console.WriteLine("Квадрат числа {0} равен  {1}",
                                              par, sdr);

       Console.WriteLine("Удвоенное значение числа {0} равно
                                            {1}"
, par, add);

       string s = Console.ReadLine();

  }

}

Рисунок 2

В методе  Main вначале создадим объект делегата delCalculate , передав конструктору делегата в качестве параметра метод Square класса Calculation . Переменной sdr присвоим значение квадрата переменной par путем обращения к делегату delCalculate и передачи ему параметра par . Далее создадим новый объект делегата delCalculate , передав конструктору делегата в качестве параметра метод Add класса Calculation. Переменной add присвоим удвоенное значение переменной par путем обращения к делегату delCalculate и передачи ему параметра par .

Результат выполнения программы приведен на рис.3.

Рисунок  3

Делегаты можно применять с анонимными методами.

Анонимный метод – это блок кода, используемый в качестве параметра делегата.

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

DelegateCalculate delCalculate = delegate (double x)

{ return x * x;};

Когда создается экземпляр delCalculate делегата DelegateCalculate, то вместо передачи ему метода (в приведенном выше примере – Calculation.Square) используется простой блок кода:

{ return x * x;}

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

На использование анонимных методов имеются ряд ограничений: запрещается использовать управляющие операторы перехода (break, goto, continue) из анонимных методов к коду, находящемуся вне их тела; не допускается передача управления в тело анонимного метода извне.

Пример использования делегатов. Необходимо реализовать сортировку экземпляров клиентского класса по различным полям. Для сортировки применяется алгоритм пузырьковой сортировки. Данный алгоритм предполагает сравнение двух экземпляров класса с целью определения экземпляра меньшего по заданному критерию и последовательную перестановку элементов сортируемого списка.

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

delegate bool CompareOp(object lhs, object rhs);

Сигнатуру метода сортировки Sort() определим следующим образом:

static public void Sort(object[] sortArray, CompareOp gtMethod)

Параметр sortArray задает массив сортируемых объектов (в рассматриваемом примере массив экземпляров класса Employee), а параметр gtMethod – метод, принимающий два параметра и возвращающий true, если значение его второго параметра больше значения первого параметра.

На рис.4 приведен код класса BubbleSorter , имеющий статический метод Sort().

class BubbleSorter

{

 static public void Sort(object[] sortArray, CompareOp gtMethod)

   {for (int i = 0; i < sortArray.Length; i++)

       {for (int j = i + 1; j < sortArray.Length; j++)

           {if (gtMethod(sortArray[j], sortArray[i]))

               {   object temp = sortArray[i];

                   sortArray[i] = sortArray[j];

                   sortArray[j] = temp;

               }

           }

       }

   }

}

Рисунок 4

На рис. 5 приведен код класса Employee.  Класс имеет три метода RhsIsCreaterId, RhsIsCreaterSalary, RhsIsCreaterDate, которые осуществляют сравнение двух экземпляров класса Employee соответственно по коду, дате приема на работу и заработной плате.

class Employee

{

   int id;                    // Идентификационный номер

   string name;               // Фамилия, имя

   decimal salary;            // Размер заработной платы

   DateTime dateOfEmployment; // Дата приема на работу

// Конструктор класса Employee

   public Employee(int id, string name, decimal salary,

                           DateTime dateOfEmployment)

   {   this.id = id;

       this.name = name;

       this.salary = salary;

       this.dateOfEmployment = dateOfEmployment; }

   /// Результат сравнения по коду

   public static bool RhsIsCreaterId(object lhs, object rhs)

   {   Employee empLhs = (Employee)lhs;

       Employee empRhs = (Employee)rhs;

       return (empRhs.id > empLhs.id) ? true : false; }

   /// Результат сравнения по заработной плате

   public static bool RhsIsCreaterSalary(object lhs,
                                         
object rhs)

   {   Employee empLhs = (Employee)lhs;

       Employee empRhs = (Employee)rhs;

       return (empRhs.salary > empLhs.salary) ? true : false;}

   /// Результат сравнения по дате приема на работу

   public static bool RhsIsCreaterDate(object lhs, object rhs)

   {   Employee empLhs = (Employee)lhs;

       Employee empRhs = (Employee)rhs;

       return (empRhs.dateOfEmployment >
                                  empLhs.dateOfEmployment) ? true : false;}

   

   public override string ToString()

   { return string.Format("{0}  код - {1, 2}"+

     " дата приема - {2,2}.{3,2}.{4,4}"+

    "  зарплата {5, 10:C2}",

    name.PadRight(18), id, dateOfEmployment.Day,

    dateOfEmployment.Month, dateOfEmployment.Year, salary);}

}

Рисунок 5

Методы возвращают значение  true , если второй экземпляр класса Employee, задаваемый вторым параметром методов, превосходит по заданному критерию первый экземпляр класса, задаваемый первым параметром методов, и возвращают false – в противном случае. Два параметра методов представляют собой объектные ссылки, которые в теле методов приводятся к типу экземпляра класса Employee.

Для тестирования класса  BubbleSorter совместно с классом Employee создадим клиентский код, приведенный на рис.6.

Результаты выполнения программы клиентского кода приведены на рис.7.

В рассмотренном примере конструкция делегата применена для построения гибкого и эффективного программного решения для сортировки объектов различной структуры.


using
System;

using System.Collections.Generic;

using System.Text;

namespace TestDelegate2

{public delegate bool CompareOp(object lhs, object rhs);

class Program

{    static void Main(string[] args)

   { Employee[] employees =

           {  new Employee(5, "Иванов Иван", 50000,
                              
new DateTime(2001,10,12)),

               new Employee(2, "Петров Петр", 150000,
                              
new DateTime(2002,12, 12)),

               new Employee(7, "Квасов Александр", 80000,
                               
new DateTime(2000, 08,17)),

               new Employee(3, "Шевцов Павел", 90000,
                               
new DateTime(2006, 06,06)),

               new Employee(8, "Калинин Алексей", 70000,
                                
new DateTime(1999,08,15)),

               new Employee(10, "Бочаров Константин",
                        100000,
new DateTime(2001,10,18))

           };

       CompareOp empCompareOp =
                    
new CompareOp(Employee.RhsIsCreaterId);

       BubbleSorter.Sort(employees, empCompareOp);

       Console.WriteLine("\nСортировка по коду");

       for (int i = 0; i < employees.Length; i++)

           Console.WriteLine(employees[i].ToString());

       string s = Console.ReadLine();

       Console.WriteLine("\nСортировка по дате приема на
                                                   работу"
);

       empCompareOp = new CompareOp(Employee.RhsIsCreaterDate);

       BubbleSorter.Sort(employees, empCompareOp);

       for (int i = 0; i < employees.Length; i++)

           Console.WriteLine(employees[i].ToString());

       Console.WriteLine("\nСортировка по заработной плате");

       empCompareOp =
                 
new CompareOp(Employee.RhsIsCreaterSalary);

       BubbleSorter.Sort(employees, empCompareOp);

       for (int i = 0; i < employees.Length; i++)

           Console.WriteLine(employees[i].ToString());

       string s = Console.ReadLine();

   }

}

}

Рисунок 6

Рисунок 7

1  Сигнатура метода определяет возвращаемое значение, имя метода, количество и типы параметров


 

А также другие работы, которые могут Вас заинтересовать

80561. Використання і контроль обігового капіталу 72 KB
  Ефективність використання оборотного капітал може бути досягнення шляхом прискорення їх обертання. Шляхи прискорення обігу оборотних активів для вивільнення оборотних коштів
80562. Банківське кредитування підприємств 165.5 KB
  Слово «кредит» походить від латинського, що означає борг, позика. В сучасному понятті кредит - це капітал, який береться під позику у вигляді грошової форми і надається в тимчасове використання госпорганам на умовах забезпеченості, повернення, терміновості, оплати та цільового використання.
80563. Небанківське і міжнародне кредитування підприємств 280 KB
  Комерційний кредит — це одна з найперших форм кредитних відносин в економіці, саме він породив вексельний обіг і тим самим сприяв розвитку безготівкового грошового обігу. Основна мета комерційного кредиту — прискорення процесу реалізації товарів і отримання закладеного в них прибутку.
80564. Фінансове забезпечення інвестиційної діяльності 104 KB
  Згідно закону України Про інвестиційну діяльність інвестиції усі види майнових та інтелектуальних цінностей що вкладаються в обєкти підприємницької та фінансової діяльності в результаті чого створюється прибуток або досягається соціальний ефект. інвестиції це вкладення капіталу в обєкти підприємницької діяльності з метою забезпечення його зростання у майбутньому. Інвестиції розрізняють за видами. Фінансові інвестиції це активи які утримує підприємство з метою отримання прибутку за рахунок відсотків дивідендів зростання вартості...
80565. Оцінка ефективності інвестицій 180 KB
  Ефективність дохідність довготермінових облігацій може бути виміряна у вигляді: купонної дохідності норма відсотка облігації; ставки розміщення річної ставки складних відсотків. Ставка розміщення найбільш точно характеризує реальну фінансову ефективність облігації враховуючи всі види доходів від неї. Отже завдання вимірювання фінансової ефективності облігації зводиться до обчислення ставки розміщення у вигляді річної ставки складних відсотків. Нарахування відсотків за цією ставкою на ціну придбання облігації яка може відрізнятись від...
80566. Особливості фінансів малого бізнесу 232 KB
  Малий бізнес є найбільш поширеним сектором економіки. Відмінності між цими трьома видами бізнесу обумовлені різним рівнем суспільного поділу праці, характером спеціалізації га усуспільнення виробництва, а також вибором технологічного типу виробничого процесу.
80568. Направления совершенствования расчетного и кассового обслуживания клиентуры в Новоуренгойском отделении Сберегательного банка №8369 707.5 KB
  Сберегательный Банк Российской Федерации – старейший банк страны. Созданный в 1841 году как финансовый институт для малоимущих слоёв населения, он и по сегодняшний день остаётся единственным банком, который обслуживает наименее обеспеченные группы физических лиц.
80569. Процесс перевозки грузов автомобильным транспортом на примере ОО УМ «Газпромдорстрой» 718 KB
  Автомобильный транспорт состоит на пороге больших перемен. Меняются требования к его работе. Необходимо поднять использование автомобилей на новый более качественный уровень развития...