2010-12-08 7 views
1

Возможно, я немного переоценил это, но я мог бы использовать некоторую помощь в определении способа/наилучшего способа сделать следующее.Capture Variable Into EventHandler

У меня есть обработчик событий, который привязан к объекту, который является свойством другого класса. В моем обработчике событий мне нужны дополнительные метаданные об объекте, вызвавшем событие (т. Е. Идентификатор объекта, в котором он содержится). От отправителя и информации о событиях нет способа получить необходимую мне информацию. Моя склонность заключалась в том, что это было бы хорошим местом для использования захваченной переменной, но я не уверен в своих идеях реализации.

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

void MyEventHandler(object sender, EventArgs e){ 
    //Do Stuff here 
} 

(Как примечание, я использую базу EventArgs здесь, но в моей фактической реализации АРЕ специализированный подкласс и событие объявляется с помощью общий EventHandler)

Сейчас я прилагая это так:

topObject.SubObject.EventToHandle += MyEventHandler; 

позже я detatch его следующим образом:

topObject.SubObject.EventToHandle -= MyEventHandler; 

Я хочу topObject идентификационному, когда я обработки события, так что я собирался изменить MyEventHandler иметь следующую подпись:

void MyEventHandler(int id, object sender, EventArgs e) 

и присоединить обработчик событий, как это:

topObject.SubObject.EventToHandle += (s,e) => MyEventHandler(topObject.ID, s,e); 

Моя забота о том, что это два раза.

  1. Возникла проблема с областью действия, при которой обработчик фактически исчезнет без удаления, когда я окажусь вне функции, где это присоединено. Я видел некоторые странные ошибки в прошлом, когда обработчик событий исчез на мне, когда я использовал выражение лямбда. Это не всегда, просто в некоторых случаях. Может ли кто-нибудь просветить меня о том, что могут быть в таких случаях, поэтому я знаю, когда можно было использовать синтаксис, который у меня был.
  2. Я точно не помню, но я не думаю, что когда-нибудь удастся удалить обработчик событий, если я использую этот синтаксис, потому что неявный объект, который создается, не то же самое.

Из-за этих двух проблем моя мысль заключалась в том, чтобы создать действие и сохранить действие и использовать его, пока мне не понадобится удалить обработчик событий. Я сделал следующее:

Action<object, EventArgs> handler = (s,e) => MyEventHandler(topObject.ID, s,e); 
topObject.SubObject.EventToHandle += handler; 

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

ответ

1

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

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

0

событие обработчик подпись в классе повышение события должна быть:

protected void OnMyEvent(object sender, EventArgs e) 
{ 
    .... 
} 

или

protected void OnMyEvent(object sender, MyEventArgs e) 
{ 
    .... 
} 

В этом случае абонент будет делать этот вид кода:

topObject.SubObject.MyEvent -= OnSubObjectMyEvent; 

и реализовать OnSubObjectMyEvent, как это (пример):

private void OnSubObjectMyEvent(object sender, MyEventArgs e) 
{ 
    int topObjectId = ((SubObjectType)sender).TopObject.Id; 
    ... 
} 

Здесь я полагаю, что SubObject имеет свойство TopObject, которое позволяет мне получить идентификатор верхнего объекта.

Так работают большинство классов .NET Framework. Что-то не так с этим подходом?

+1

Что с этим подходом является Я работа с объектами, которые я не контролирую, и подобъект не знает о его объекте topobject. Если бы у меня был такой доступ, это было бы неконтактным – 2010-12-09 13:17:38

0

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

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

void Handler(object sender, EventArgs e) 
{ 
    var s = (SubObject) sender; 
    int id = s.TopObject.ID; 

    // do something with id... 
} 

Я хотел бы сохранить подписи событий в конвенции отправителя и аргументах.

0

Не изменяйте подпись мероприятия. Хотя CLR позволяет, технически, для любой подписи к событию, есть причины, по которым весь Framework был разработан с событиями, имеющими подпись (object sender, EventArgs args). На самом деле, существует правило FxCop для событий, которые нарушают эту подпись, CA1009: Declare event handlers correctly:

Методы обработчика события принимают два параметры. Первый имеет тип System.Object и имеет имя 'sender'. Это объект, который поднял событие . Второй параметр имеет тип System.EventArgs и имеет имя 'e'.

Есть несколько решений (альтернатив):

  • пройти topObject.ID как член пользовательских EventArgs.
  • создать объект-оболочку, который инкапсулирует topObject.ID и привязывает обработчик события к методу этого объекта.
  • использовать закрывающий объем, который может сохранить ссылку на topObject.ID в области видимости (которая совпадает с описанным выше способом, но heavylifting делается компилятором)