В прошлой статье, посвященной работе с C# я попытался разработать простенький класс для преобразования координат из географической системы в декартову и обратно. При этом, как я и сказал в конце статьи, я рассмотрел далеко не все аспекты работы с классами. Так, например, я обошел стороной темы работы с событиями в классах, хотя этот вопрос (использование событий в классах) является едва ли не ключевым при проектировании приложений. Однако, чтобы плавно перейти к событиям в классах необходимо рассмотреть ещё один тип данных C# — делегаты.
Надо сказать, что тема делегатов в C#, наверное, одна из самых сложных для таких новичков, как я. Помниться, первое моё знакомство с делегатами в C# стало причиной по которой я забросил изучение C# в теперь уже далеком 2011 году. Надеюсь, что теперь смогу в ней разобраться.
Делегаты в C#
Итак, что такое делегат, согласно справочнику от Microsoft:
Делегат — это тип данных, который представляет ссылки на методы с определенным списком параметров и типом возвращаемого значения.
Собственно, для тех, кто имел дело с ссылками на методы в Delphi уже после прочтения этого официального определения все должно стать более менее понятным и остается только рассмотреть как эти самые делегаты описываются на языке C# и, в дальнейшем, используются в тех же событиях классов.
Объявляется делегат следующим образом:
public delegate void DelegateName(args);
то есть, вначале идёт один из модификаторов доступа, далее — ключевое слово delegate, затем тип возвращаемого значения (в примере — void, то есть ничего не возвращаем),затем — имя делегата и в круглых скобках аргументы (перечень параметров).
Объект делегата обычно создается путем указания имени метода, для которого делегат будет служить оболочкой, или с помощью анонимной функции.
Для работы с делегатами в C# можно выделить четыре шага:
- Объявить делегат
- Создать метод, на который будет ссылаться делегат
- Создать переменную для этого делегата
- Вызвать метод делегата.
Первый делегат C#: переписываем «Hello world»
Чтобы понять как работать с делегатами в C#, я решил переписать наше первое приложение «Hello world» с использованием новых для меня знаний, то есть вывести на экран строку «Hello world» при помощи делегатов. В итоге получился следующий код:
using System; namespace DelegateExample { //объявляем делегат public delegate void WriteLine(string Text); class Program { //создаем метод на ссылка на который будет передаваться делегату static void MyDelegeteMethod(string Line) { Console.WriteLine(Line); } static void Main(string[] args) { //создаем переменную типа делегата и указываем ссылку на метод WriteLine handl = MyDelegeteMethod; //вызываем метод handl("Hello world!!!"); Console.ReadLine(); } } }
В этом примере новым для меня стал модификатор static для метода MyDelegeteMethod. Модификатор static используется для объявления статического члена, принадлежащего собственно типу, а не конкретному объекту, то есть, объявление в C# типа:
static void MyDelegeteMethod(string Line)
аналогично следующему объявлению в Delphi
class procedure(Line: string);
в каком-либо классе.
Использование делегатов в качестве параметров других методов
Так как делегат относится к ссылочному типу данных, то делегаты можно передавать в качестве параметров в других методах. Например, немного усложним наш пример с делегатом и пусть он используется в качестве параметра метода,который складывает два числа:
using System; namespace DelegateExample { //объявляем делегат public delegate void WriteLine(string Text); class Program { //создаем метод ссылка на который будет передаваться делегату static void MyDelegeteMethod(string Line) { Console.WriteLine(Line); } //в этом методе делегат используется в качестве параметра public static void MethodWithCallback(int param1, int param2, WriteLine callback) { callback("Сумма чисел: " + (param1 + param2).ToString()); } static void Main(string[] args) { //создаем переменную типа делегата и указываем ссылку на метод WriteLine handl = MyDelegeteMethod; //вызываем метод с делегатом в качестве параметра MethodWithCallback(1,2, handl); Console.ReadLine(); } } }
Теперь метод с именем MethodWithCallback использует делегат в качестве параметра и на экран будет выводиться сумма двух чисел.
Многоадресность
Ещё один интересный, на мой взгляд, момент при работе с делегатами в C#. При вызове делегат может вызывать сразу несколько методов. Это называется многоадресностью.
Чтобы добавить в список методов делегата (список вызова) дополнительный метод, необходимо просто добавить два делегата с помощью оператора сложения или назначения сложения («+» или «+=»).
Например, нам необходимо вывести на экран результаты сложения, умножения и деления двух чисел целочисленного типа. Сделаем это с помощью двух делегатов — один у нас уже есть (выводит строку на экран), а второй будет принимать в качестве параметров два числа и производить с ними соответствующие операции.
using System; namespace DelegateExample { //объявляем делегат для вывода строк в консоль public delegate void WriteLine(string Text); //объявляем делегат для работы с числами public delegate void Calculate(int A, int B, WriteLine callback); class Program { //создаем метод ссылка на который будет передаваться делегату WriteLine static void MyDelegeteMethod(string Line) { Console.WriteLine(Line); } /*Методы для делегата Calculate*/ //этот метод будет складывать два числа и выводить результат в консоль static void Add(int A, int B, WriteLine callback) { callback("Сумма двух чисел: "+(A + B).ToString()); } //этот метод будет умножать два числа static void Multiplication(int A, int B, WriteLine callback) { callback("Произведение двух чисел: " + (A * B).ToString()); } //этот метод будет делить два числа static void Division(int A, int B, WriteLine callback) { callback("Частное двух чисел: " + ((float)A / B).ToString()); } static void Main(string[] args) { //создаем переменную для вывода строки WriteLine callback; callback = MyDelegeteMethod; //создаем переменные типа делегата и указываем ссылку на метод Calculate d1 = Add; Calculate d2 = Multiplication; Calculate d3 = Division; //назначаем переменной несколько методов Calculate handl = d1 + d2 + d3; handl(1, 2, callback); Console.ReadLine(); } } }
Здесь у нас делегат Calculate принимает также в качестве аргумента другой делегат (для вывода строки на экран). В переменной handl мы сложили все три делегата, а затем последовательно вызвали все три метода — сложение, умножение и деление. Результат работы программы на рисунке ниже:
Не лишним будет напомнить про результат деления двух целых чисел. Чтобы на экран не выводился 0 вместо 0,5, первое число было приведено к типу float.
Соответственно, раз мы можем складывать между собой несколько делегатов, то справедливым будет и обратное действие — вычитание. Например, исключить сложение в нашем примере можно вот так:
//просто для примера вызываем метод callback("Исключаем сложение: "); //исключаем из списка один из делегатов handl -= d1; //повторяем вызовы handl(3,5,callback);
Итог
Итак, сегодня мы рассмотрели основы работы с делегатами в C#, научились их создавать, передавать делегатам ссылки на методы, складывать и вычитать делегаты и передавать делегаты в качестве параметров для других методов. В принципе, полученных знаний должно хватить, чтобы разобраться с работой с событиями в C#. Хотя, стоит ещё раз подчеркнуть, что делегаты — это достаточно тяжелая тема и разбираться с ней придётся ещё, видимо, ни один раз.
Книжная полка
![]() |
Описание: практическое руководство познакомит вас с простыми рекомендациями, помогающими писать программное обеспечение, которое легко поддерживать и адаптировать. Написанная консультантами компании Software Improvement Group книга содержит ясные и краткие советы по применению рекомендаций на практике. Примеры для этого издания написаны на языке C#, но существует аналогичная книга с примерами на языке Java.
|
![]() |
![]() |
Название: C#. Советы программистам
Описание: Книга представляет собой сборник советов, алгоритмов и готовых примеров программ на языке C# в среде MS Visual Studio 2005/2008 из различных областей: работа с формами и элементами управления, папками и файлами, мышью и клавиатурой, мультимедиа и графикой, использование технологий WMI и WSH, взаимодействие с MS Office и другими приложениями, работа в локальной сети и Интернете, особенности использования функций Windows API и др.
|
![]() |



