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


 

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

79341. Хімічна мозаїка 69.5 KB
  Мета: показати різноманітність хімічних речовин, їх широке застосування у господарській діяльності людини, у побуті; у ігровій формі вивчити формули речовин; познайомити учнів із шкідливим впливом деяких з них.
79342. Через терни до зірок 779.5 KB
  Мета: зацікавити учнів космонавтикою, фізикою, астрономією. Розповісти про вчених – земляків, які освоювали космос. Розвивати інтерес учнів, розширити кругозір, формувати уміння аналізувати, робити висновки. Виховувати патріотичні почуття, гордість за співвітчизників.
79344. Площадь прямоугольника 30.1 KB
  Цели урока: формирование совокупности компетенций, необходимых для вычисления площади прямоугольника развивать мыслительные операции; воспитывать прилежание, аккуратность, стремление к выполнению всех заданий; уважение друг к другу...
79345. Гуморальная регуляция физиологических функций. Физиология желез внутренней секреции 192.5 KB
  Изучить закономерности гуморальной регуляции механизмы действия гормонов структурно-функциональную организацию эндокринной системы виды и функции гормонов желез внутренней секреции: щитовидной паращитовидных поджелудочной половых вилочковой надпочечников и эпифиза.
79346. ПЕРВЫЙ ЗВОНОК 60 KB
  В первый день сентября всем радость даря Каждый раз повторяется это Каждый собрался солнышком согрет Только первого класса что-то нет Вед: Нет первый класс здесь и с нетерпением ждет когда его позовут на линейку ведь первоклассники сегодня самые главные действующие лица праздника.