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

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

  • автор:

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

Примичание: Доступа к редактированию классов 1 и 2 нету, также в классе 3 вызывать базовый конструктор обязательно.
Спасибо за помощь.
Писал по памяти, если есть вопросы спрашивайте.

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

Как отписаться от события чтобы не было утечки памяти
Здравствуйте, подскажите как отписаться от события чтобы не было утечки памяти. Все равно после.

Отписаться от события/форсированное освобождение объекта
Добрый день. Использую у себя CSScript. К примеру, скрипт выглядит так: public class Script .

Как отписаться от подписок удаляемому объекту
Всем привет!) Встретил в инфу, что при удалении экземпляра отменяются подписки на события этого.

Эксперт .NET

17413 / 12809 / 3355
Регистрация: 17.09.2011
Сообщений: 21,087

1 2 3 4 5 6 7 8
class Class3 : Class2 { public Class3(): base() { FieldName.Event1 -= method1; } }

Но в этом случае придется сделать метод method1 публичным или защищенным.

Как вариант, в классе Class2 можно сделать защищенный метод для отписывания:

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 28
class Class2 { private Class1 _fieldName; public Class1 FieldName { get { this._fieldName } } public Class2() { this._fieldName.Event1 += new System.EventHandler(method1); } private void method1(object sender, EventArgs e) { } protected void Unsubscribe() { this._fieldName.Event1 -= method1; } } class Class3 : Class2 { public Class3(): base() { Unsubscribe(); } }

Добавлено через 41 секунду

ЦитатаСообщение от xWinDx Посмотреть сообщение

Доступа к редактированию классов 1 и 2 нету
Ой, не заметил примечания.
Ну тогда труба — придется как-то делать через рефлексию.
Регистрация: 28.03.2010
Сообщений: 99

Да в том то и дело. через reflection я нашёл MethodInfo нужного метода, я просто низнаю, что мне счас делат с этим MethodInfo, как отписать.

Добавлено через 4 часа 0 минут
. UP

Почетный модератор

Эксперт .NET

8717 / 3669 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9

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 28 29 30 31 32 33 34 35
class Class2 { public event EventHandler Args; public Class2( ) { this.Args += new EventHandler( this.method1 ); } public void Call() { if ( Args != null ) Args( null, null ); } private void method1( object sender, EventArgs e ) { MessageBox.Show( "!" ); } } class Class3 : Class2  public Class3( ) : base( ) { base.Call(); // для проверки var methodInfo = typeof( Class2 ).GetMethod("method1", BindingFlags.NonPublic  }

Регистрация: 28.03.2010
Сообщений: 99
Спасибо, помогло. Можете закрывать!
447 / 300 / 65
Регистрация: 12.10.2009
Сообщений: 1,162

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

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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { interface IMethod { void Method(object sender, EventArgs e); } class Class1 { public event EventHandlerEventArgs> EventMetod = delegate { }; public void FireEvent() { EventMetod(this, new EventArgs()); } } class Class2:IMethod { private Class1 class1; public event EventHandlerEventArgs> EventMethod { add { class1.EventMetod += value; } remove { class1.EventMetod -= value; } } public Class2() { class1 = new Class1(); this.EventMethod += new EventHandlerEventArgs>(((IMethod)this).Method); FireEvent(); } public void FireEvent() { class1.FireEvent(); } void IMethod.Method(object sender, EventArgs e) { Console.WriteLine("Test. "); } } class Class3:Class2 { public Class3():base() { this.EventMethod -= new EventHandlerEventArgs>(((IMethod)this).Method); FireEvent(); } } class Program { static void Main(string[] args) { Class3 obj = new Class3(); } } }

метод FireEvent служит для проверки корректности зажигания события, в случае вызова Class2.FireEvent событие Class1.EventMethod вызывает пользовательский обработчик, а в в случае вызова Class3.FireEvent событие Class1.EventMethod не вызывает пользовательский обработчик, в тоже время Class2.IMethod.Method являеться закрытым, как того тебе и хочеться

Добавлено через 11 минут
а на счет нет доступа к редактированию. ну если у ты можешь вызвать рефлексию для класса, значит доступ к классу имеется, SAE и Reflector тебе в руки. декомпилировать и собрать свою собственную либу, иногда поверь это намного проще чем возиться с рефлексией, неизвестно чем аукнуться шаманские танцы с рефлексией

Добавлено через 1 минуту
так к примеру разработчики изменят сигнатуру вызова и будешь ты долго и без успешно ловить баг в рунтайме

Как отписаться от события, если в качестве подписки лямбда выражение?

Ведь есть же возможность получить дескриптор функции из самой функции, подобно this внутри объекта, для получения дескриптора этого объекта?

  • Вопрос задан более трёх лет назад
  • 7163 просмотра

Комментировать
Решения вопроса 2

BasmanovDaniil

Даниил Басманов @BasmanovDaniil
Геймдизайнер-телепат
Храните ссылку на анонимный метод.

public delegate void TestEventHandler(object sender, object e); public event TestEventHandler TestEvent; TestEventHandler test = null; test = (sender, e) => < TestEvent -= test; >; TestEvent += test;

Ответ написан более трёх лет назад
Нравится 2 3 комментария
iRumba @iRumba Автор вопроса
мне отписаться надо внутри лямбда выражения. Кажется, в вопросе это ясно сказано.

BasmanovDaniil

Даниил Басманов @BasmanovDaniil
Обновил ответ
iRumba @iRumba Автор вопроса

AlekseyNemiro

Алексей Немиро @AlekseyNemiro
full-stack developer
Проще всего запомнить ссылку и не извращаться:

// создаем переменную типа EventHandler EventHandler handler = null; // создаем анонимный метод для обработки события и передаем его переменной handler = (sender, e) => < MessageBox.Show("Hello!"); // удаляем обработчик ((Button)sender).Click -= handler; >; // добавляем обработчик button1.Click += handler;

Плохое решение может выглядеть так:

// добавляем обработчик button1.Click += (sender, e) => < MessageBox.Show("Hello!"); // получаем поле EventClick var f = typeof(Control).GetField ( "EventClick", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static ); // получаем значение EventClick для sender var k = f.GetValue(sender); // получаем свойство var p = sender.GetType().GetProperty ( "Events", BindingFlags.NonPublic | BindingFlags.Instance ); // получаем значение свойства Events для sender var events = (EventHandlerList)p.GetValue(sender, null); // удаляем обработчик из списка событий events.RemoveHandler(k, events[k]); >;

В собственных классах проще получить список делегатов при помощи GetInvocationList (внутри класса):

public class Toster < public event EventHandler AnyEvent; public void AnyEventHarakiri() < foreach (Delegate d in this.AnyEvent.GetInvocationList()) < this.AnyEvent -= (EventHandler)d; >> >
var t = new Toster(); t.AnyEvent += (sender, e) => < >; t.AnyEventHarakiri();

Но вариант со ссылками лучше.
Ответ написан более трёх лет назад
Нравится 2 3 комментария
iRumba @iRumba Автор вопроса

ссылка не доступна внутри лямбда функции (см комментарий в прошлом сообщении). Первый вариант не подходит

второй и третий варианты удалят всех подписчиков. Это тоже плохо.

Есть еще варианты?

AlekseyNemiro

Алексей Немиро @AlekseyNemiro

MoreBeauty: если нужно удалить что-то конкретное, то хочешь не хочешь, придется его как-то идентифицировать. Проще всего ссылки использовать. Можно создать список обработчиков, с какими-нибудь ключами для идентификации, и удалять по ключам.

Первый вариант работает, в том виде, в котором я его представил.
Если при объявлении переменной передавать ей анонимный метод, то работать не будет. Поэтому сначала идет объявление, затем присвоение значения.
Если не работает, то нужен код. Я проверял все представленные примеры кода с кнопками, всё работает.

Нужно ли отписываться от событий

К примеру у нас есть некая типизированная коллекция. У элементов этой коллекции есть какие-то собития, которые эта самая коллекция должна отслеживать (то есть при добавлении элемента происходит подписка).

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

Соберется ли этот объект сборщиком мусора или будет считаться, что коллекция все еще содержит на него ссылку?

][tiger

Ну и сам уже отвечу Если ссылок больше нет, то GC соберет этот объект и без отписки от событий. Ведь на самом деле, это сам объект ссылается на делегат. Однако, для коллекции все-таки нужно отписаться.

admin

Для: ][tiger
интересный подход

Dr.Gigabit


GC соберет этот объект и без отписки от событий
[snapback]32240″ rel=»nofollow» target=»_blank[/snapback]​
[snapback]32240″ rel=»nofollow» target=»_blank[/snapback]​

Не уловил мысли

][tiger

Мысль такова, что если мы подписаны на событие какого-то объекта, но ссылок больше на него нет, то GC соберет его как мусор.

В случае с коллекцией — если объект удаляют из коллекции (а значит коллекция больше не должна обрабатывать события объекта), то существует вероятность, что ссылка на этот объект у кого-то остается и после удаления из коллекции. Тогда коллекция будет все еще обрабатывать события этого объекта (потому что он не уничтожился).

Сам себе ответил на вопрос потому, что догадался запустить SnippetCompiler набросать пример и проверить — будет ли объект собираться GC, если ссылок нет, но есть подписчики. Ответ — будет.

Можно ли как-то отписать всех от события? C#

В C# нет прямого способа отписать всех подписчиков от события с помощью синтаксиса типа `Method -= MyAction;`. Однако, существует несколько способов, как можно отписать всех подписчиков от события:

1. Создание нового экземпляра события: Один из способов отписать всех подписчиков от события — создать новый экземпляр события. Это можно сделать путем создания нового экземпляра делегата для события. Например:

«`csharp
event Action MyEvent = null;
«`

При этом все предыдущие подписки на событие `MyEvent` будут потеряны, и новые подписчики должны будут заново подписаться на событие.

2. Использование рефлексии: Другой способ — использовать рефлексию для получения списка подписчиков и удаления каждого из них вручную. Это более сложный и не рекомендуемый подход, так как рефлексия может быть медленной и неэффективной во время выполнения.

«`csharp
// Получение информации о событии с помощью рефлексии
EventInfo eventInfo = typeof(YourClass).GetEvent(«MyEvent»);
// Получение текущих подписчиков события
Delegate[] subscribers = eventInfo.GetInvocationList();
// Отписка от события для каждого подписчика
foreach (Delegate subscriber in subscribers)
eventInfo.RemoveEventHandler(this, subscriber);
>
«`

Обратите внимание, что использование рефлексии может быть сложным и подвержено ошибкам, поэтому не рекомендуется применять его в обычных сценариях.

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

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