Передайте возвращаемое значение обратно через EventHandler
Я пытаюсь написать API, и мне нужно вызвать обработчик событий, когда я получаю данные из таблицы. Что-то вроде этого:
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 методу), но я просто не могу получить синтаксис правильно.
Любое предложение очень ценится.
Ответы
Ответ 1
Общий шаблон здесь заключается не в том, чтобы возвращать какие-либо данные из обработчика событий, а в том, чтобы добавить свойства к объекту аргумента события, чтобы получатель события мог установить свойства, к которым затем может обратиться вызывающий объект. Это очень распространено в коде обработки пользовательского интерфейса; Вы видите концепцию отмены событий повсюду.
Ниже приведен псевдокод, и он не готов к компиляции. Его цель - показать шаблон.
public class 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;
}
Edit
Мне нравится, как Джон Скит сформулировал это так: сделать EventArgs
взаимозаменяемым. Таким образом, потребитель события может изменить состояние объекта EventArgs
, позволяя источнику события получить эти данные.
Ответ 2
Я знаю, что это старый пост, но на всякий случай кто-то сталкивается с этим, это, безусловно, возможно сделать. Вы объявляете своего делегата, который возвращает значение, а затем основывайте событие на этом новом делетете. Вот пример:
В случае declarer/publisher:
// 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 о событии AssemblyResolve
Я лично использовал как событие AssemblyResolve, так и пользовательский метод делегирования для возврата данных из события, и оба они работают как ожидается в Visual Studio 2010.
Ответ 3
Единственный способ сделать это - сделать один из аргументов (желательно "args", а не отправителя) изменчивым. Если он уже не изменен, у вас в основном возникают проблемы - просто нет способа получить информацию.
(Хорошо, там один способ - вы можете держать аргумент события неизменным, но сделать его одним из них методом, который в конечном итоге вызывает делегата, зарегистрированного кодом, поднимающим событие в первую очередь. Но это ужасно...)
Ответ 4
Простым решением является использование замыкания:
public override bool Run() {
SomeInfo someInfo = ...
table.WhenData += (obj, args) => {
someInfo.Return = something
};
}