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


 

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

78760. Книга та комп’ютер – наші друзі 112 KB
  Адже це дійсно так. Особливо ці слова, сказані англійським прем’єр міністром у минулому столітті, є актуальними сьогодні. У наш час стрімкого розвитку інноваційних технологій дуже важливо володіти своєчасною та актуальною інформацією. З кожним роком обсяг інформації зростає, також скорочується час для пошуку інформації.
78761. Хай сонцю і квітам всміхаються діти 717.5 KB
  Організаційна робота. Прийом дітей в пришкільний табір. Знайомство з вожатими та дітьми Знайомство з вожатими. Хто запам’ятав, як звуть вожатих? Знайомство-жарт з дітьми. З нами ви вже познайомились. А тепер ми хочемо познайомитись з вами. Я рахую до трьох, на рахунок «три» кожний викрикує своє ім’я.
78762. У Марійки Підгірянки, мов із золота співанки 80 KB
  Однак незважаючи на її велике бажання вчитися батько -– незаможний лісник не міг дати освіту всім дітям тому в сімейному колі вирішили що вчитися буде син а дівчатка займатимуться хатньою роботою. Допомагав дочці батько котрий досконало володів німецькою мовою добре знав математику біологію.
78763. ЛІТЕРАТУРНИЙ ВЕЧІР ЗА ТВОРАМИ ГРИЦЬКА БОЙКА 73 KB
  Добрий день, дорогі гості. Ми дуже раді, що ви прийшли на наше свято. Ми зможемо сьогодні розвеселити вас і зробити вам приємне, значит наша праця не буде марною. Як відомо, кожна людина ставить перед собою завдання і намагається його виконати.
78764. Бармен. Особливості приготування коктейлів 1.39 MB
  Професію бармена відносять до типу професій «людина — людина», тому що головним предметом праці для неї є людина, а головною метою праці цієї професії є оперативне обслуговування відвідувачів та розрахунок з ними.
78765. Конструювання радіоелектронного засобу 674.24 KB
  Коли на комутатор телефонної станції надходить виклик він повідомляє про вхідний дзвінок абонента шляхом подачі змінного струму на дроти що ведуть до викликається телефонному апарату. У режимі очікування коли трубка лежить на важелі спеціальний пристрій зване конденсатором...
78766. Правове регулювання електронної комерції в Україні. Національне законодавство та міжнародні стандарти 134.5 KB
  Матеріали дослідження можуть бути використані для розширення методологічної бази правових галузевих досліджень. Одержані результати можуть бути використані: у практиці правозастосування з метою подолання існуючих проблем та методичних рекомендацій; для проведення подальших теоретичних...
78767. Технологія перевезення вугілля морським транспортом 110.4 KB
  Метою даного дипломного проекту полягає у висвітленні наступних завдань: Ознайомитись з транспортною характеристикою вугілля; Встановити особливості перевезення вугілля морським транспортом; З’ясувати характеристику ринку вугілля.
78768. Створення форонтиспісу у програмі Photshop 2.36 MB
  З усіх видів криття брошур основним є криття врозпуск при якому на обкладинці роблять чотири рубчики і приклеюють її не тільки до корінця а й до першої сторінки блока. Комбіноване фальцювання Формат видання це розмір сторінки видання після обрізки блока по ширині і довжині.