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  Сигнатура метода определяет возвращаемое значение, имя метода, количество и типы параметров


 

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

77448. Совершение сделок по приобретению более 30% акций ОАО (поглощение АО) 16.74 KB
  Добровольное предложение также может содержать сделанное владельцам эмиссионных ценных бумаг конвертируемых в акции предложение приобрести у них такие ценные бумаги. Перечень сведений указанных в добровольном предложении устанавливается ФЗ Об АО Срок принятия добровольного предложения срок в течение которого заявление о продаже ценных бумаг должно быть получено лицом направившим добровольное предложение который не может быть менее чем 70 дней и более чем 90 дней с момента получения добровольного предложения открытым обществом; К...
77449. Соотношение терминов «несостоятельность» и «банкротство» 33.5 KB
  В само определение банкротства входит несостоятельность должника. Не всегда приводит к судебному подтверждению банкротства должника. Общая характеристика законодательства о несостоятельности банкротстве Возникновение ситуации неплатежеспособности у должника приводит к ситуации выбора относительно требований кредитора. С момента возбуждения данного процесса погашение долгов должника возможность только в специальном порядке установленном законом.
77451. Круг лиц, которые имеют право обратиться в суд с заявлением о банкротстве 37.5 KB
  Федерального закона о банкротстве правом на обращение в арбитражный суд с заявлением о признании должника банкротом обладают должник конкурсный кредитор уполномоченные органы. Право на обращение в арбитражный суд возникает у конкурсного кредитора уполномоченного органа по денежным обязательствам с даты вступления в законную силу решения суда арбитражного суда или третейского суда о взыскании с должника денежных средств. Должник вправе подать в арбитражный суд заявление должника в случае предвидения банкротства при наличии обстоятельств...
77453. Реестр требований кредиторов 56 KB
  Если количество конкурсных кредиторов требования которых включены в реестр превышает 500. Решение о привлечении реестродержателя и о выборе конкретного реестродержателя принимается собранием кредиторов. Общее правило если собрание кредиторов определит иной источник за этот счёт.
77454. Понятие, цель и порядок введения процедуры, применяемой в деле о банкротстве: наблюдение. Временный управляющий, его права и обязанности 18.89 KB
  Приостанавливается производство по делам о взыскании денежных средств с должника. Собственник имущества унитарного предприятия не вправе изымать его у должника. 6 нельзя выплачивать дивиденды и принимать решения которые приводят к уменьшению активов должника. Введение наблюдения по общему правилу не прекращает полномочия органов управления должника.
77455. Понятие, цель и порядок введения процедуры, применяемой в деле банкротстве: финансового оздоровление. Последствия ее введения ее 16.57 KB
  План финансового оздоровления это письменный документ представляется учредителями должника собственникам имущества должника утверждается собранием кредиторов. Должен обосновать возможность удовлетворения требований кредиторов. Требования обязательные...
77456. Понятие, цель и порядок введения процедуры, применяемой в деле о банкротстве: внешнего управления. Последствия введения внешнего управления 26.88 KB
  Последствия введения внешнего управления. План внешнего управления. Отчет внешнего управляющего и прекращение внешнего управления.