Как отписаться от события c
Перейти к содержимому

Как отписаться от события c

  • автор:

Руководство по программированию на C#. Подписка и отмена подписки на события

Необходимость подписки на событие, опубликованное другим классом, может возникнуть, когда требуется написать пользовательский код, вызываемый при инициировании такого события. Например, можно подписаться на событие кнопки click , чтобы приложение выполняло некоторое действие при нажатии пользователем кнопки.

Подписка на события в интегрированной среде разработки Visual Studio

  1. Если окно Свойства закрыто, в представлении Конструктор щелкните правой кнопкой мыши форму или элемент управления, для которого требуется создать обработчик событий, и выберите пункт Свойства.
  2. Вверху окна Свойства щелкните значок События.
  3. Дважды щелкните событие, которое требуется создать, например событие Load . Visual C# создаст пустой метод обработчика событий и добавит его в код. Код можно также добавить вручную в представлении Код. Например, приведенные ниже строки кода объявляют метод обработчика событий, который будет выполнен при вызове классом Form события Load .
private void Form1_Load(object sender, System.EventArgs e) < // Add your form load event handling code here. >

Строка кода, требуемая для подписки на событие, также создается автоматически в методе InitializeComponent в файле Form1.Designer.cs проекта. Она имеет следующий вид:

this.Load += new System.EventHandler(this.Form1_Load); 

Подписка на события программными средствами

  1. Определите метод обработчика событий, сигнатура которого соответствует сигнатуре делегата для события. Например, если событие основано на типе делегата EventHandler, то следующий код представляет заглушку метода:
void HandleCustomEvent(object sender, CustomEventArgs a) < // Do something useful here. >
publisher.RaiseCustomEvent += HandleCustomEvent; 

Чтобы указать обработчик событий, можно также воспользоваться лямбда-выражением:

public Form1() < InitializeComponent(); this.Click += (s,e) =>< MessageBox.Show(((MouseEventArgs)e).Location.ToString()); >; > 

Подписка на события с помощью анонимной функции

Если вам не нужно будет позже отменять подписку на событие, можно использовать оператор присваивания сложения ( += ) для привязки анонимной функции как обработчика событий. В следующем примере предположим, что объект с именем publisher имеет событие с именем RaiseCustomEvent и что класс CustomEventArgs также был определен и содержит некие относящиеся к событию сведения. Обратите внимание на то, что классу подписчика требуется ссылка на publisher , чтобы подписаться на его события.

publisher.RaiseCustomEvent += (object o, CustomEventArgs e) => < string s = o.ToString() + " " + e.ToString(); Console.WriteLine(s); >; 

Отменить подписку на событие не так просто, если для подписки использовалась анонимная функция. Чтобы отменить подписку в этом случае, в коде, где была выполнена подписка на событие, сохраните анонимную функцию в переменной делегата, а затем добавьте делегат к событию. Мы рекомендуем не использовать анонимные функции для подписки на события, если в будущем вам нужно будет отменить подписку. Дополнительные сведения об анонимных функциях см. в статье Лямбда-выражения.

Отмена подписки

Чтобы предотвратить вызов обработчика событий при инициировании события, подписку на событие необходимо отменить. Во избежание утечки ресурсов отменять подписку на события следует до удаления объекта подписчика. До тех пор пока подписка на событие не отменена, делегат многоадресной рассылки, лежащий в основе события в публикующем объекте, будет ссылаться на делегат, инкапсулирующий обработчик событий подписчика. Если ссылка присутствует в публикующем объекте, объект подписчика не будет удален при сборке мусора.

Отмена подписки на событие
  • Чтобы отменить подписку на событие, воспользуйтесь оператором присваивания вычитания ( -= ).
publisher.RaiseCustomEvent -= HandleCustomEvent; 

См. также

  • События
  • event
  • Практическое руководство. Публикация событий, соответствующих рекомендациям .NET
  • Операторы — и -=
  • Операторы + и +=

Совместная работа с нами на GitHub

Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.

.remove Event Listener ( )

Удаляет обработчик события с элемента, установленный с помощью add Event Listener ( ) .

Как пишется

Скопировать ссылку «Как пишется» Скопировано

Добавим обработчик на элемент, а затем удалим его.

Например, будем обрабатывать клики на любое место на странице, а затем удалим обработчик, передав в remove Event Listener ( ) те же аргументы, что и при добавлении:

 function handleMouseClick(event)  console.log('Вы нажали на элемент:', event.target)> // Добавляем обработчик событияwindow.addEventListener('click', handleMouseClick) // Убираем обработчик событияwindow.removeEventListener('click', handleMouseClick) function handleMouseClick(event)  console.log('Вы нажали на элемент:', event.target) > // Добавляем обработчик события window.addEventListener('click', handleMouseClick) // Убираем обработчик события window.removeEventListener('click', handleMouseClick)      

Метод remove Event Listener ( ) принимает три аргумента. Первые два обязательные:

  • название события строкой;
  • функция-обработчик, которую нужно убрать с указанного события.

Третий аргумент необязательный — это объект с настройками в котором могут содержаться свойства capture и passive с булевыми значениями true либо false . Точно такие же опции, можно передать и в .add Event Listener ( ) .

 window.addEventListener('click', handleMouseClick,  capture: true, passive: true>) // Аналогичные опции при удалении обработчикаwindow.removeEventListener('click', handleMouseClick,  capture: true, passive: true>) window.addEventListener('click', handleMouseClick,  capture: true, passive: true >) // Аналогичные опции при удалении обработчика window.removeEventListener('click', handleMouseClick,  capture: true, passive: true >)      

Переданные настройки влияют на удаление обработчика события. Мы рекомендуем повторять в точности те же параметры, которые использовались в .add Event Listener ( ) , чтобы браузер точно знал какой обработчик нужно удалить.

Например, создадим обработчик события и передадим третьим аргументом в опциях значение true . Если попробовать убрать событие, но ничего не передать в опциях в .remove Event Listener ( ) , то событие не уберётся.

 function handleMouseClick(event)  console.log('Вы нажали на элемент:', event.target)> window.addEventListener('click', handleMouseClick, true) // Ничего не передаем в опциях в третьем аргументеwindow.removeEventListener('click', handleMouseClick) function handleMouseClick(event)  console.log('Вы нажали на элемент:', event.target) > window.addEventListener('click', handleMouseClick, true) // Ничего не передаем в опциях в третьем аргументе window.removeEventListener('click', handleMouseClick)      

Аналогичная ситуация, если делать наоборот.

Как понять

Скопировать ссылку «Как понять» Скопировано

Браузер даёт возможность не только устанавливать обработчик события, но и убирать их.

Очищать обработчики событий важно, потому что каждый обработчик занимает место в памяти и выполняется всякий раз, когда срабатывает событие. Если не убирать неиспользуемые обработчики событий, то можно столкнуться с неожиданным поведением. Например, один из старых обработчиков будет мешать всплытию события наверх, и другой обработчик не будет работать.

Хорошим тоном считается убирать обработчик сразу же, как он перестал быть нужен.

Будет ли на самом деле удалён обработчик события зависит от того, какую функцию и какие опции передали вторым и третьим аргументами в .remove Event Listener ( ) .

Функции относятся к ссылочным типам данных, а значит две одинаково написанные функции будут считаться различными. Поэтому, если ранее в .add Event Listener ( ) использовалась анонимная функция, то убрать обработчик с помощью .remove Event Listener ( ) не получится.

 window.addEventListener('click', (event) =>  console.log('Клик!')>) // Обработчик не будет удалён!window.removeEventListener('click', (event) =>  console.log('Клик!')>) window.addEventListener('click', (event) =>  console.log('Клик!') >) // Обработчик не будет удалён! window.removeEventListener('click', (event) =>  console.log('Клик!') >)      

Всегда сохраняйте функцию-обработчик в переменную чтобы позже убрать обработчик. Делать это необязательно только если вы делаете быстрый прототип или проверяете свою идею прямо в браузере.

Браузер сравнивает опции, когда ищет обработчик события для удаления. Посмотрим ещё раз на пример выше, когда в .add Event Listener ( ) передали в опциях true , а в .remove Event Listener ( ) нет опций.

 function handleMouseClick(event)  console.log('Вы нажали на элемент:', event.target)> window.addEventListener('click', handleMouseClick, true) // Обработчик не удалится, потому что опции не совпадаютwindow.removeEventListener('click', handleMouseClick) function handleMouseClick(event)  console.log('Вы нажали на элемент:', event.target) > window.addEventListener('click', handleMouseClick, true) // Обработчик не удалится, потому что опции не совпадают window.removeEventListener('click', handleMouseClick)      

Так происходит потому что третий аргумент неявно устанавливается в undefined , а undefined превращается в false при конвертации в булевый тип. Когда браузер ищет обработчик на удаление, он сравнивает опции и видит, что true ! = = false , значит обработчик не будет удалён.

На практике

Скопировать ссылку «На практике» Скопировано

Егор Огарков советует

Скопировать ссылку «Егор Огарков советует» Скопировано

�� Автоматическое очищение обработчика после первого срабатывания

Если нужно чтобы событие сработало только один раз, то можно не использовать remove Event Listener ( ) , а использовать опцию once в add Event Listener ( ) .

 window.addEventListener('click', function (event)  console.log('Клик!')>, < once: true >) window.addEventListener('click', function (event)  console.log('Клик!') >,  once: true >)      

При первом клике обработчик сработает, а затем автоматически удалится. В этом случае можно даже использовать анонимную функцию, так как не нужно очищать обработчик вручную.

�� Можно написать очищение обработчика в самом обработчике событий

Когда в браузерах не было возможности использовать опцию < once : true >при установке обработчика события, такое поведение делали самостоятельно:

 function handleClick(event)  console.log('Клик!') // Сразу же очищаем после вызова функции, // обработчик сработает только один раз window.removeEventListener('click', handleClick)> window.addEventListener('click', handleClick) function handleClick(event)  console.log('Клик!') // Сразу же очищаем после вызова функции, // обработчик сработает только один раз window.removeEventListener('click', handleClick) > window.addEventListener('click', handleClick)      

Другим примером может быть очищение обработчика по определённому условию. Добавим обработчик события клавиатуры, но по нажатию клавиши Esc будет очищать его.

 function handleKeypress(event)  console.log('Нажата клавиша:', event.key) if (event.key === 'Escape')  window.removeEventListener('keypress', handleKeypress) >> window.addEventListener('keypress', handleKeypress) function handleKeypress(event)  console.log('Нажата клавиша:', event.key) if (event.key === 'Escape')  window.removeEventListener('keypress', handleKeypress) > > window.addEventListener('keypress', handleKeypress)      

События! Как грамотно подписаться/отписаться?

У меня возникли воросы на который я, к сожалению, не нашел однозначного ответа. Есть два класса A , B . У класса B есть public ObservableCollection , у которого есть событие CollectionChanged . Я подисываюсь на данное событие из класса A и B .

B.ObservableCollection.CollectionChanged += Hello; this.ObservableCollection.CollectionChanged += Hello1; 
  1. Как грамотно отписать всех подписок в классе A от события?
  2. Как грамотно отписать всех подписок в классе B от события?
  3. Почему считается плохим тоном отписываться так: CollectionChanged = null ? Что произойдет?

Отслеживать
задан 7 июл 2018 в 2:50
299 2 2 серебряных знака 11 11 бронзовых знаков
3. Это разве сработает?
7 июл 2018 в 6:55
@АндрейNOP Я незнаю, потому и спрашиваю, что произойдет. 🙂 Я пологаю John дал ответ на это.
7 июл 2018 в 9:22

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Если ссылок на объект к которому мы подписались больше нет, то объект будет собран сборщиком мусора => отписка произойдет автоматически=> беспокоится в этом случае не нужно.

Однако, если у вас долгоживущие объекты и в определенным периоды вы хотите слушать, а в какие-то нет, то отписывайтесь явно.

Отслеживать
ответ дан 7 июл 2018 в 5:38
24.8k 13 13 золотых знаков 66 66 серебряных знаков 163 163 бронзовых знака
Это точно? Подписчик не хранит ссылку на объект?
7 июл 2018 в 6:55

Я думаю, что да. А зачем подписчику хранить ссылку на издателя? Издатель хранит адреса функций, которые должен вызвать при наступлении события.

7 июл 2018 в 7:05

Ну да, согласен, там связь обратная, тот кто предоставляет события, хранит ссылки на подписчиков (точнее делегат хранит ссылку на класс, в котором он определен)

7 июл 2018 в 7:09

Для начала нужно чётко понимать, как работают события и делегаты. Когда вы подписываетесь, то передаёте событию делегат на метод, который он будет впоследствии вызывать. То есть связь однонаправленная classA -> eventA -> delegateB -> сlassB и в результате из класса B мы не можем знать, подписано что-то на него или нет.

1) Для подписки/отписки от события между разными экземплярам классов есть множество путей и у каждого свои плюсы и минусы. Вот почитайте про события подробнее. Расписывать здесь не вижу смысла, но прочитать эту статью рекомендую.

2) Если происходит подписка метода на событие одного экземпляра класса, то отписывать не нужно. Так как в результате у вас событие будет вести на тот же класс и сборщик мусора, если не имеется других ссылок на этот класс, удалит его.

3) От события можно отписывать сразу всех через присвоение null, проблема лишь в том, что это возможно только из класса, которому это событие принадлежит. Для всех других классов доступно лишь два метода Add и Remove, то есть подписка (добавления делегата) и отписка (удаление делегата). В вашем случае у вас присвоить null не получится, так как CollectionChanged принадлежит ObservableCollection, к которому изнутри у вас нет доступа.

Как отписаться от события c

События сигнализируют системе о том, что произошло определенное действие. И если нам надо отследить эти действия, то как раз мы можем применять события.

Например, возьмем следующий класс, который описывает банковский счет:

class Account < // сумма на счете public int Sum < get; private set; >// в конструкторе устанавливаем начальную сумму на счете public Account(int sum) => Sum = sum; // добавление средств на счет public void Put(int sum) => Sum += sum; // списание средств со счета public void Take(int sum) < if (Sum >= sum) < Sum -= sum; >> >

В конструкторе устанавливаем начальную сумму, которая хранится в свойстве Sum. С помощью метода Put мы можем добавить средства на счет, а с помощью метода Take, наоборот, снять деньги со счета. Попробуем использовать класс в программе — создать счет, положить и снять с него деньги:

Account account = new Account(100); account.Put(20); // добавляем на счет 20 Console.WriteLine($"Сумма на счете: "); account.Take(70); // пытаемся снять со счета 70 Console.WriteLine($"Сумма на счете: "); account.Take(180); // пытаемся снять со счета 180 Console.WriteLine($"Сумма на счете: ");
Сумма на счете: 120 Сумма на счете: 50 Сумма на счете: 50

Все операции работают как и положено. Но что если мы хотим уведомлять пользователя о результатах его операций. Мы могли бы, например, для этого изменить метод Put следующим образом:

public void Put(int sum) < Sum += sum; Console.WriteLine($"На счет поступило: "); >

Казалось, теперь мы будем извещены об операции, увидев соответствующее сообщение на консоли. Но тут есть ряд замечаний. На момент определения класса мы можем точно не знать, какое действие мы хотим произвести в методе Put в ответ на добавление денег. Это может вывод на консоль, а может быть мы захотим уведомить пользователя по email или sms. Более того мы можем создать отдельную библиотеку классов, которая будет содержать этот класс, и добавлять ее в другие проекты. И уже из этих проектов решать, какое действие должно выполняться. Возможно, мы захотим использовать класс Account в графическом приложении и выводить при добавлении на счет в графическом сообщении, а не консоль. Или нашу библиотеку классов будет использовать другой разработчик, у которого свое мнение, что именно делать при добавлении на счет. И все эти вопросы мы можем решить, используя события.

Определение и вызов событий

События объявляются в классе с помощью ключевого слова event , после которого указывается тип делегата, который представляет событие:

delegate void AccountHandler(string message); event AccountHandler Notify;

В данном случае вначале определяется делегат AccountHandler, который принимает один параметр типа string. Затем с помощью ключевого слова event определяется событие с именем Notify, которое представляет делегат AccountHandler. Название для события может быть произвольным, но в любом случае оно должно представлять некоторый делегат.

Определив событие, мы можем его вызвать в программе как метод, используя имя события:

Notify("Произошло действие");

Поскольку событие Notify представляет делегат AccountHandler, который принимает один параметр типа string — строку, то при вызове события нам надо передать в него строку.

Однако при вызове событий мы можем столкнуться с тем, что событие равно null в случае, если для его не определен обработчик. Поэтому при вызове события лучше его всегда проверять на null. Например, так:

if(Notify !=null) Notify("Произошло действие");
Notify?.Invoke("Произошло действие");

В этом случае поскольку событие представляет делегат, то мы можем его вызвать с помощью метода Invoke() , передав в него необходимые значения для параметров.

Объединим все вместе и создадим и вызовем событие:

class Account < public delegate void AccountHandler(string message); public event AccountHandler? Notify; // 1.Определение события public Account(int sum) =>Sum = sum; public int Sum < get; private set; >public void Put(int sum) < Sum += sum; Notify?.Invoke($"На счет поступило: "); // 2.Вызов события > public void Take(int sum) < if (Sum >= sum) < Sum -= sum; Notify?.Invoke($"Со счета снято: "); // 2.Вызов события > else < Notify?.Invoke($"Недостаточно денег на счете. Текущий баланс: "); ; > > >

Теперь с помощью события Notify мы уведомляем систему о том, что были добавлены средства и о том, что средства сняты со счета или на счете недостаточно средств.

Добавление обработчика события

С событием может быть связан один или несколько обработчиков. Обработчики событий — это именно то, что выполняется при вызове событий. Нередко в качестве обработчиков событий применяются методы. Каждый обработчик событий по списку параметров и возвращаемому типу должен соответствовать делегату, который представляет событие. Для добавления обработчика события применяется операция += :

Notify += обработчик события;

Определим обработчики для события Notify, чтобы получить в программе нужные уведомления:

Account account = new Account(100); account.Notify += DisplayMessage; // Добавляем обработчик для события Notify account.Put(20); // добавляем на счет 20 Console.WriteLine($"Сумма на счете: "); account.Take(70); // пытаемся снять со счета 70 Console.WriteLine($"Сумма на счете: "); account.Take(180); // пытаемся снять со счета 180 Console.WriteLine($"Сумма на счете: "); void DisplayMessage(string message) => Console.WriteLine(message);

В данном случае в качестве обработчика используется метод DisplayMessage, который соответствует по списку параметров и возвращаемому типу делегату AccountHandler. В итоге при вызове события Notify?.Invoke() будет вызываться метод DisplayMessage, которому для параметра message будет передаваться строка, которая передается в Notify?.Invoke() . В DisplayMessage просто выводим полученное от события сообщение, но можно было бы определить любую логику.

Если бы в данном случае обработчик не был бы установлен, то при вызове события Notify?.Invoke() ничего не происходило, так как событие Notify было бы равно null.

Консольный вывод программы:

На счет поступило: 20 Сумма на счете: 120 Со счета снято: 70 Сумма на счете: 50 Недостаточно денег на счете. Текущий баланс: 50 Сумма на счете: 50

Теперь мы можем выделить класс Account в отдельную библиотеку классов и добавлять в любой проект.

Добавление и удаление обработчиков

Для одного события можно установить несколько обработчиков и потом в любой момент времени их удалить. Для удаления обработчиков применяется операция -= . Например:

Account account = new Account(100); account.Notify += DisplayMessage; // добавляем обработчик DisplayMessage account.Notify += DisplayRedMessage; // добавляем обработчик DisplayRedMessage account.Put(20); // добавляем на счет 20 account.Notify -= DisplayRedMessage; // удаляем обработчик DisplayRedMessage account.Put(50); // добавляем на счет 50 void DisplayMessage(string message) => Console.WriteLine(message); void DisplayRedMessage(string message) < // Устанавливаем красный цвет символов Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(message); // Сбрасываем настройки цвета Console.ResetColor(); >
На счет поступило: 20 На счет поступило: 20 На счет поступило: 50

В качестве обработчиков могут использоваться не только обычные методы, но также делегаты, анонимные методы и лямбда-выражения. Использование делегатов и методов:

Account acc = new Account(100); // установка делегата, который указывает на метод DisplayMessage acc.Notify += new Account.AccountHandler(DisplayMessage); // установка в качестве обработчика метода DisplayMessage acc.Notify += DisplayMessage; // добавляем обработчик DisplayMessage acc.Put(20); // добавляем на счет 20 void DisplayMessage(string message) => Console.WriteLine(message);

В данном случае разницы между двумя обработчиками никакой не будет.

Установка в качестве обработчика анонимного метода:

Account acc = new Account(100); acc.Notify += delegate (string mes) < Console.WriteLine(mes); >; acc.Put(20);

Установка в качестве обработчика лямбда-выражения:

Account account = new Account(100); account.Notify += message => Console.WriteLine(message); account.Put(20);

Управление обработчиками

С помощью специальных акссесоров add/remove мы можем управлять добавлением и удалением обработчиков. Как правило, подобная функциональность редко требуется, но тем не менее мы ее можем использовать. Например:

class Account < public delegate void AccountHandler(string message); AccountHandler? notify; public event AccountHandler Notify < add < notify += value; Console.WriteLine($"добавлен"); > remove < notify -= value; Console.WriteLine($"удален"); > > public Account(int sum) => Sum = sum; public int Sum < get; private set; >public void Put(int sum) < Sum += sum; notify?.Invoke($"На счет поступило: "); // 2.Вызов события > public void Take(int sum) < if (Sum >= sum) < Sum -= sum; notify?.Invoke($"Со счета снято: "); // 2.Вызов события > else < notify?.Invoke($"Недостаточно денег на счете. Текущий баланс: "); ; > > >

Теперь опредление события разбивается на две части. Вначале просто определяется переменная делегата, через которую мы можем вызывать связанные обработчики:

AccountHandler notify;

Во второй части определяем акссесоры add и remove. Аксессор add вызывается при добавлении обработчика, то есть при операции +=. Добавляемый обработчик доступен через ключевое слово value . Здесь мы можем получить информацию об обработчике (например, имя метода через value.Method.Name) и определить некоторую логику. В данном случае для простоты просто выводится сообщение на консоль:

add < notify += value; Console.WriteLine($"добавлен"); >

Блок remove вызывается при удалении обработчика. Аналогично здесь можно задать некоторую дополнительную логику:

remove < notify -= value; Console.WriteLine($"удален"); >

Внутри класса событие вызывается также через переменную notify. Но для добавления и удаления обработчиков в программе используется как раз Notify:

Account acc = new Account(100); acc.Notify += DisplayMessage; // добавляем обработчик DisplayMessage acc.Put(20); // добавляем на счет 20 acc.Notify -= DisplayMessage; // удаляем обработчик DisplayMessage acc.Put(20); // добавляем на счет 20 void DisplayMessage(string message) => Console.WriteLine(message);

Консольный вывод программы:

DisplayMessage добавлен На счет поступило: 20 DisplayMessage удален

Передача данных события

Нередко при возникновении события обработчику события требуется передать некоторую информацию о событии. Например, добавим и в нашу программу новый класс AccountEventArgs со следующим кодом:

class AccountEventArgs < // Сообщение public string Message// Сумма, на которую изменился счет public int Sum public AccountEventArgs(string message, int sum) < Message = message; Sum = sum; >>

Данный класс имеет два свойства: Message — для хранения выводимого сообщения и Sum — для хранения суммы, на которую изменился счет.

Теперь применим класс AccoutEventArgs, изменив класс Account следующим образом:

class Account < public delegate void AccountHandler(Account sender, AccountEventArgs e); public event AccountHandler? Notify; public int Sum < get; private set; >public Account(int sum) => Sum = sum; public void Put(int sum) < Sum += sum; Notify?.Invoke(this, new AccountEventArgs($"На счет поступило ", sum)); > public void Take(int sum) < if (Sum >= sum) < Sum -= sum; Notify?.Invoke(this, new AccountEventArgs($"Сумма снята со счета", sum)); > else < Notify?.Invoke(this, new AccountEventArgs("Недостаточно денег на счете", sum)); >> >

По сравнению с предыдущей версией класса Account здесь изменилось только количество параметров у делегата и соответственно количество параметров при вызове события. Теперь делегат AccountHandler в качестве первого параметра принимает объект, который вызвал событие, то есть текущий объект Account. А в качестве второго параметра принимает объект AccountEventArgs, который хранит информацию о событии, получаемую через конструктор.

Теперь изменим основную программу:

Account acc = new Account(100); acc.Notify += DisplayMessage; acc.Put(20); acc.Take(70); acc.Take(150); void DisplayMessage(Account sender, AccountEventArgs e) < Console.WriteLine($"Сумма транзакции: "); Console.WriteLine(e.Message); Console.WriteLine($"Текущая сумма на счете: "); >

По сравнению с предыдущим вариантом здесь мы только изменяем количество параметров и их использования в обработчике DisplayMessage. Благодаря первому параметру в методе можно получить информацию об отправителе события — счете, с которым производится операция. А через второй параметр можно получить инфомацию о состоянии операции.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *