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

4 чел.

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


 

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

80426. СОЗДАНИЕ МОБИЛЬНОГО ИНФОРМАЦИОННОГО РЕСУРСА 143 KB
  В рамках данной дипломной работы будет описан процесс создания мобильной версии информационного ресурса Яковлевской центральной детской библиотеки в городе Строитель ориентированной в частности на учащихся средних школ Яковлевского района Белгородской области.
80427. Принцип разделения властей и его реализация к Конституции Российской федерации 1993-го года 127 KB
  Суть данного принципа заключается в том, чтобы не допустить узурпации власти в руках главы одной ветви власти, чтобы размеренно, путём системы сдержек и противовесов, одна ветвь власти влияла на другую, контролировала и выявляла недостатки в управлении, взаимодействовала, чтобы один орган не оказался таком положении...
80429. Финансово-правовое стимулирование инвестиционной деятельности в субъекте Российской Федерации (на примере Томской области) 43.13 KB
  Как известно, рыночная экономика функционирует по принципу естественного отбора. Но уровень развития производственной, иной хозяйственной деятельности на соответствующей территории едва ли можно назвать исключительно частным делом – ведь от этого зависит уровень жизни проживающих в этой местности граждан.
80430. Компетенция Конституционных ( уставных ) судов Субъектов РФ 111 KB
  Конституции Российской Федерации на основании этих положений разводиться компетенциальный вопрос но вопрос о компетенции и юрисдикции конституционных уставных судов в РФ с судами общей юрисдикцией а именно с публичным производством представляется довольно интересным применительно...
80431. Физическая культура и спорт. Волейбол 1.35 MB
  Товарищеские это неофициальные встречи которые проводятся по взаимной договоренности с целью определения степени подготовленности отдельных игроков и команды в целом к предстоящим соревнованиям а также степени усвоения программного материала.
80432. КЛАССИФИКАЦИЯ НАУК 74.5 KB
  Выявление структуры науки в этом ее аспекте ставит проблему классификации наук раскрытие их взаимосвязи на основании определенных принципов и критериев и выражение их связи в виде логически обоснованного расположения в определенный ряд структурный срез.