Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.86/35: Рейтинг темы: голосов - 35, средняя оценка - 4.86
55 / 13 / 2
Регистрация: 26.10.2014
Сообщений: 1,107

Делегаты и события

25.02.2017, 03:02. Показов 7053. Ответов 13
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте.
В C# есть такие 2 темы, как делегаты и события.
Я попробовал их изучить, даже код рабочий, но я не понимаю сути. Зачем, как и почему.
Делегаты:
Делегаты я понимаю только так:
Есть функция
C#
1
public void MyFunction(int a, int b)
А делегат это как бы ссылка на эту функцию.
То есть объявляем делегат с такой же сигнатурой:
C#
1
public delegate void MyDelegate(int a, int b);
Потом инициализируем делегат:
C#
1
MyDelegate md = new MyDelegate(MyFunction);
]
И теперь можем обращаться к функции как:
C#
1
md(4, 4);
Но непонятно. Зачем?
события:
Как я понимаю, события вызываются при каких то условиях. Например Tick, прошла секунда, Click нажата кнопка и проч.
Использовать готовые события и назначать обработчики не вопрос. А вот делать свои... Вопросы, вопросы, вопросы...
Плиз, знающие, поясните всю данную ситуацию, и желательно с примером задачи, где без делегатов и событий никак. Покажите и объясните на примере их использование.
Заранее Благодарен!
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
25.02.2017, 03:02
Ответы с готовыми решениями:

Для чего использовать ключевое слово event в объявлении события, если события — это те же самые делегаты
Господа, скажите пожалуйста, для чего использовать ключевое слово event в объявлении события, если события - это те же самые делегаты ?...

Делегаты и события
Доброго времени суток уважаемые, очень туго идет освоение delegate and event, создал небольшую программку, с таким заданием: (Разработал ...

делегаты и события
Здравствуйте! Помогите пожалуйста с задачей: Есть два делегата: delegate void SimpleDel(string str); delegate void ValueChangeDel(int...

13
Заблокирован
25.02.2017, 03:21
Цитата Сообщение от jonikster Посмотреть сообщение
Но непонятно. Зачем?
Например, чтобы выбрать, какую функцию вызывать не во время компиляции, а во время работы программы.
0
55 / 13 / 2
Регистрация: 26.10.2014
Сообщений: 1,107
25.02.2017, 03:33  [ТС]
Как это? Мы же сразу функцию указываем при инициализации делегата.
0
Заблокирован
25.02.2017, 03:48
Цитата Сообщение от jonikster Посмотреть сообщение
Как это? Мы же сразу функцию указываем при инициализации делегата.
Это ты сразу указываешь и так видишь со своей колокольни. А код, который потом ее вызывает, он не в курсе, что там вообще за функция, он просто вызывает делегат. Код, вызывающий делегат не меняется, никакие имена не меняются. А функция, которая в итоге будет вызвана может меняться.

Добавлено через 5 минут
Возьми самый обычный WinForms. Допустим есть объект кнопка. Допустим, грубо, у него есть делегат Клик, которые вызывается, когда пользователь кликает на кнопке. Работа кода класса кнопки - просто вызвать делегат. Что там - ему пофиг. Работа программиста - сделать свою функцию или 10 функций и привязать нужную функцию к делегату Клик нужного объекта. Потом по какому-нибудь условию во время работы он вообще может привязать другую функцию к тому же делегату. Класс кнопки ничего об это не знает, он не меняется, и это удобно.

Добавлено через 1 минуту
Или я хочу сделать массив из функций. Как это сделать без делегатов?

Добавлено через 3 минуты
Что угодно, что вызывает переданную от программиста функцию - использует делегаты. Есть у меня функция, которая принимает параметром другую функцию, чтобы ее вызвать. Как это сделать? Делегат.
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
25.02.2017, 03:52
jonikster,
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// функция, считающая сумму сходящегося ряда
double Sum(Func<int, double> sequence)
{
    double sum = 0;
    
    for (int i = 1; sequence(i) > 1e-8; i++)
        sum += sequence(i);
        
    return sum;
}
 
static void Main()
{
    Console.WriteLine(Sum(k => 1 / Math.Pow(2, k)));
    Console.WriteLine(Sum(k => 1 / Math.Pow(k, 2)));
}
0
55 / 13 / 2
Регистрация: 26.10.2014
Сообщений: 1,107
25.02.2017, 04:25  [ТС]
с делегатами более менее понятно.
А что с событиями?
0
9 / 9 / 13
Регистрация: 15.03.2016
Сообщений: 32
25.02.2017, 06:27
Цитата Сообщение от jonikster Посмотреть сообщение
А что с событиями?
например, ты пишешь класс, который загружает какие то файлы с ФТП. Это единственная его задача. Тогда, чтобы оповестить о прогрессе загрузки или о ее завершении создаются соответствующие события. Предположим у тебя есть GUI и два разных класса для обработки полученных файлов. Тогда GUI подписывается на оба события, а экземпляры классов на событие завершения загрузки.
Вот пример. Создаю делегат и событие:
C#
1
2
3
4
5
public class FtpDownloadManager
    {
        public delegate void DownloadProgressEventHandler(string fileName, ProgressChangedEventArgs args);
        public static event DownloadProgressEventHandler DownloadProgressEvent;
}
Затем при загрузке файла и чтении потока с ФТП вызываю событие после каждой порции данных:
C#
1
DownloadProgressEvent?.Invoke(item.Name, new ProgressChangedEventArgs((int)(istream.Position / (double)istream.Length * 100), null));
А где то в основной программе подписываюсь на это событие:
C#
1
2
3
4
FtpDownloadManager.DownloadProgressEvent += (name, progress) =>
            {
                Console.Write($"\rDownloading \'{name}\': {progress.ProgressPercentage}%");
            };
Т.е. идея в том, что класс FtpDownloadManager абсолютно ничего не знает, что будет дальше происходить с полученными файлами и каким образом и где будет отображаться прогресс загрузки. Он просто сообщает об этом с помощью события, а те, кто подписан на эти события уже сами решают что с этим делать.
0
55 / 13 / 2
Регистрация: 26.10.2014
Сообщений: 1,107
25.02.2017, 09:25  [ТС]
Смысл событий как бы понятен, и как работают тоже. Но опять делегаты сбивают.
0
 Аватар для kesean
292 / 291 / 108
Регистрация: 04.09.2010
Сообщений: 638
25.02.2017, 09:53
Цитата Сообщение от jonikster Посмотреть сообщение
А что с событиями?
Например, есть у тебя класс, выполняющий какую-то задачу в фоновом режиме. Вызывающему классу (родителю) надо знать, когда он ее выполнит.
Можно пойти разными путями. Передать в в этот класс ссылку на родителя, и по завершении задачи из класса вызывать какой-либо метод родителя. А можно ссылку не передавать, а подписаться на событие.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A();
            a.Completed += new A.CompletedHandler(a_Completed);
            a.DoWork();
            Console.ReadLine();
        }
 
        static void a_Completed(bool result)
        {
            if (result)
                Console.WriteLine("OK");
        }
    }
    class A
    {
        public delegate void CompletedHandler(bool result);
        public event CompletedHandler Completed;
 
        public void DoWork()
        {
            //Выполнение задачи
            if (Completed != null) Completed(true);
        }
    }
1
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
25.02.2017, 10:09
Есть тип данных делегат, пример:
C#
1
public delegate int MyDelegate(string text);
Есть экземпляры этого типа:
C#
1
2
3
MyDelegate myDelegate = s => s.Length;
myDelegate += s => s.IndexOf('a'); // теперь myDelegate - цепочка из двух методов
int indexOfA = myDelegate("bcda"); // возвращается результат вызова последнего метода из цепочки (хотя вызываются все)
Есть событие - пара методов add (+=) и remove (-=), пример бесполезного события:
C#
1
2
3
4
5
6
7
8
9
10
11
public event MyDelegate StupidEvent
{
    add
    {
        Console.WriteLine("Кто-то попытался подписаться, но мне пофиг");
    }
    remove
    {
        Console.WriteLine("Кто-то попытался отписаться - ни холодно, ни жарко");
    }
}
Такое событие невозможно вызвать, так как экземпляра делегата не существует, ну и к тому же оно не запоминает своих подписчиков.
Когда вы пишите вот так:
C#
1
public event MyDelegate UsualEvent;
компилятор генерирует что-то вроде этого:
C#
1
2
3
4
5
6
7
8
9
private MyDelegate _compilerGeneratedIdentifier;
public void add_UsualEvent(MyDelegate myDelegate) // такие методы нельзя вызвать напрямую, только с помощью '+='
{
    _compilerGeneratedIdentifier += myDelegate;
}
public void remove_UsualEvent(MyDelegate myDelegate) // '-='
{
    _compilerGeneratedIndentifier -= myDelegate;
}
Дополнительно, он позволяет вызывать делегат _compilerGeneratedIdentifier используя имя UsualEvent (только изнутри класса):
C#
1
UsualEvent("abacaba");
Главное запомнить, что событие - всего лишь пара методов, тогда взяв за основу StupidEvent, вы можете самостоятельно реализовать любую логику, срабатывающую когда где-то в коде вызываются += и -= по отношению к этому событию.
0
55 / 13 / 2
Регистрация: 26.10.2014
Сообщений: 1,107
25.02.2017, 10:19  [ТС]
Ну с событиями всё ясно. Нужна задача для примера с делегатами.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
25.02.2017, 11:12
Цитата Сообщение от jonikster Посмотреть сообщение
Ну с событиями всё ясно. Нужна задача для примера с делегатами.
События — это те же самые делегаты, но с малость урезанным функционалом.
Если вы понимаете работу делегатов, то вы понимаете и работу событий.

У них просто семантика разная:
Событие — для оповещения других объектов.
Делегат — для отвязки метода от конкретной реализации. Например, если у вас есть метод сортировки пузырьком, но способ сравнения двух объектов на больше/меньше решает тот, кто пользуется вашим методом. В этом случае вы принимаете делегат для сравнения двух объектов, который реализует ваш "клиент" под свои нужды.

А механизм работы у них один и тот же.
0
55 / 13 / 2
Регистрация: 26.10.2014
Сообщений: 1,107
25.02.2017, 12:01  [ТС]
Неа. Всё никак понять не могу.
0
9 / 9 / 13
Регистрация: 15.03.2016
Сообщений: 32
04.03.2017, 07:30
Цитата Сообщение от jonikster Посмотреть сообщение
Неа. Всё никак понять не могу.
попробуем так. в С++ есть понятие указателя. Причем указатель может быть не только на экземпляры классов/структур, но и на функции. Так называемые callback ф-ции или ф-ции обратного вызова. Так вот суть делегата та же, что и callback ф-ции.
Возьмем для примера qsort
как мы видим из кода
C++
1
2
3
4
5
6
void qsort(  
   void *base,  
   size_t num,  
   size_t width,  
   int (__cdecl *compare )(const void *, const void *)   
);
в четвертом параметре ожидается callback ф-ция, которая будет сравнивать значения. Синтаксис
C++
1
int (__cdecl *compare )(const void *, const void *)
говорит о том, что подойдет указатель на любую ф-цию, которая принимает в качестве параметров два const void * и возвращает int. поэтому можно определить такую ф-цию
C++
1
2
3
4
5
int compare_abs(const void *a, const void *b) {
   int a1 = *(int*)a;
   int b1 = *(int*)b;
   return abs(a1) - abs(b1);
}
и передать ее в качестве параметра qsort.
Попробуй почитать про callback ф-ции языка С++, возможно тогда тебе станет понятна суть делегатов.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
04.03.2017, 07:30
Помогаю со студенческими работами здесь

События и делегаты
Привет комрадс! Можете объяснить, почему не срабатывает код? Изучаю события и делегаты, есть 2 класса: 1ый общается с пользователем и...

Делегаты и события
Для данной программы добавить делегат и событие using System; using System.Collections.Generic; using System.Linq; using...

Делегаты и события
Здравствуйте, подскажите пожалуйста как переделать этот код, чтобы выводило сообщение о событии на textBox. using System; using...

Делегаты и события
using System; using System.IO; namespace Глава_15_завершение { public delegate void DelegStyd(Stydent std); public...

Делегаты и события
Помогите, я хочу с помощью += зарегистрировать в событие несколько методов, но хочу сделать так что бы в разных случаях вызывались разные ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru