2009-09-18 2 views
19

Im пытается написать в API, и мне нужно вызвать обработчик событий, когда я получаю данные из таблицы. Что-то вроде этого:Передайте возвращаемое значение обратно через EventHandler

public override bool Run(Company.API api) 
    { 
     SomeInfo _someInfo = new SomeInfo(); 

     if (_someInfo.Results == 1) 
      return true; 
     else 
      return false; 

     using (MyTable table = new MyTable(api)) 
     { 
      table.WhenData += new EventHandler<DataEventArgs<Record>>(table_WhenData); 
      table.WhenDead += new EventHandler<EventArgs>(table_WhenDead); 
      table.Start(); 
     } 

    public void table_WhenData(object sender, DataEventArgs<Record> e) 
    { 
     return true; 
    } 

Проблема, что Im имея это я не знаю, как передать значение возврата назад от table_WhenData методу Run.

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

Любое предложение очень ценится.

+0

обработчик события должен вызываться откуда-то. это не показано в вашем коде? Это единственное место, где вы можете проверить возврат от обработчика. – simon

+0

Спасибо всем.Поскольку это API, большая часть кода не имеет доступа или я не могу изменить. Я просто хотел проверить это, прежде чем отправлять его разработчикам. Спасибо. –

+2

Плюс один на имя пользователя –

ответ

38

Общий шаблон здесь заключается не в том, чтобы возвращать данные из обработчика событий, а для добавления свойств к объекту аргумента события, чтобы потребитель события мог установить свойства, к которым может обратиться вызывающий. Это очень распространено в коде обработки пользовательского интерфейса; вы видите концепцию «Отмена» по всему месту.

Ниже приведен псевдокод, а не готов к компиляции. Его цель - показать образец.

public MyEventArgs : EventArgs 
{ 
    public bool Cancel{get;set;} 
} 

public bool fireEvent() 
{ 
    MyEventArgs e=new MyEventArgs(); 

    //Don't forget a null check, assume this is an event 
    FireEventHandler(this,e); 

    return e.Cancel; 
} 

public HandleFireEvent(object sender, MyEventArgs e) 
{ 
e.Cancel=true; 
} 

Редактировать

Мне нравится, как Джон Скит сформулированный следующим образом: сделать EventArgs mutuable. То есть потребитель события может изменить состояние объекта EventArgs, позволяя рейзеру события получить эти данные.

+1

В случае, если есть несколько обработчиков событий (некоторые устанавливают его в true и другие устанавливают для этого значения объекта значение false, для примера кода, приведенного выше), как определяется код абонента события? что, как и последний абонент, который установил победы – bashahul

+1

Хороший вопрос, вы, вероятно, захотите использовать другую структуру данных в этом случае в зависимости от бизнес-правил, которые у вас есть – JoshBerke

15

Единственный способ сделать это - сделать один из аргументов (предпочтительно «args», а не отправителя) изменчивым. Если он еще не изменен, у вас в основном возникают проблемы - нет способа получить информацию.

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

+2

Голова болит, пытаясь понять один из способов, пожалуйста, сделайте EventArgs mutuable! – JoshBerke

+0

Как использовать закрытие, как описано в моем ответе? –

+0

Igor: Это сработает, но, как правило, бит кода, который требует результата, - это не бит кода, подписанный на событие. –

1

простое решение заключается в использовании закрытия:

public override bool Run() { 
    SomeInfo someInfo = ... 
    table.WhenData += (obj, args) => { 
     someInfo.Return = something 
    }; 
} 
+0

проблема, с которой я мог столкнуться в этом решении, является проблемой параллелизма. Один поток вызывает событие, а другой читает переменную someInfo до завершения записи. Для этого потребуется многопоточная защита. – simon

17

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

В разыгрывающий событие/издатель:

// the delegate 
public delegate string ReturnStringEventHandler(object sender, EventArgs args); 
// the event 
public event ReturnStringEventHandler StringReturnEvent; 
// raise the event 
protected void OnStringReturnEvent(EventArgs e) 
    { 
     if (StringReturnEvent != null) // make sure at least one subscriber 
       // note the event is returning a string 
       string myString = StringReturnEvent(this, e); 
    } 

В подписчика событий:

// Subscribe to event, probably in class constructor/initializer method 
StringReturnEvent += HandleStringReturnEvent; 

// Handle event, return data 
private string HandleStringReturnEvent(object sender, EventArgs e) 
{ 
    return "a string to return"; 
} 

.NET представляет собой пример этого в случае AssemblyResolve, который использует ResolveEventHandler делегировать данные, в этом случае ссылку на желаемую сборку. MSDN Article on AssemblyResolve event

Я лично использовал как событие AssemblyResolve и технику пользовательского делегата вернуть данные события, и они оба работают, как ожидается, на Visual Studio 2010.

+2

Если вы используете пользовательский подход делегата, что произойдет, если у вас есть несколько обработчиков события, возвращающего разные значения? Какое возвращаемое значение принимается сборщиком событий? – Shavais

+0

Вы упомянули об определенном обратном пути к этому подходу. Последним обработчиком событий, который должен быть зарегистрирован в событии, является тот, чье значение будет возвращено. http://msdn.microsoft.com/en-us/library/aa691375%28VS.71%29.aspx В событии «AssemblyResolve», о котором я упоминал, все в порядке, поскольку он предназначен только для использования по одному, но вы правы - в общем, это был бы плохой выбор дизайна, если требуется несколько возвращаемых значений. – AFischbein

+0

Блестящий. благодаря ! – BillW

Смежные вопросы