Передать возвращаемое значение обратно через EventHandler - PullRequest
30 голосов
/ 18 сентября 2009

Я пытаюсь написать в 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;
    }

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

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

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

Ответы [ 4 ]

46 голосов
/ 18 сентября 2009

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

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

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 взаимозаменяемым. Таким образом, потребитель события может изменить состояние объекта EventArgs, позволяя получателю события получить эти данные.

24 голосов
/ 07 сентября 2012

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

В объявителе / ​​издателе события:

// 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.

18 голосов
/ 18 сентября 2009

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

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

1 голос
/ 18 сентября 2009

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

public override bool Run() {
    SomeInfo someInfo = ...
    table.WhenData += (obj, args) => {
        someInfo.Return = something
    };
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...