it-roy-ru.com

Вернуть значение из события - есть ли для этого хорошая практика?

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

Мой вопрос здесь: это правильно? нормально ли возвращать значения из событий? или есть лучший способ сделать это? (например, использование простого делегата в форме для чтения значений)

36
Hugo

Часто неловко возвращать значения из событий. На практике я обнаружил, что намного проще включить доступное для записи свойство в набор пользовательских EventArgs, которые передаются событию, а затем проверяются после его запуска - аналогично свойству Cancel в событии WinForms FormClosing.

37
Dustin Campbell

Я не думаю, что это хорошая идея ... события в основном являются многоадресными делегатами, поэтому может быть несколько обработчиков Какое возвращаемое значение вы примете в этом случае?

28
Thomas Levesque

Самый близкий пример, который я могу вспомнить, это событие FormClosing в WinForms. Это позволяет форме отменить событие, установив для свойства eventArgs.Cancel значение true. Чтобы сделать что-то подобное, вы должны определить свой собственный класс args события с возвращаемым значением в качестве свойства этого класса. Затем передайте событие args объект всякий раз, когда вы вызываете событие. Кто бы ни вызвал событие, он может проверить объект args события на предмет возвращаемого значения. Другие, которые получают событие, могут также проверить или изменить объект args события.

Update: Я только что наткнулся на событие AppDomain.AssemblyResolve , и это событие, которое возвращает значение. Кажется, вам просто нужно объявить тип делегата, который возвращает значение, а затем определить ваше событие с этим типом делегата. Хотя я не пытался создать свое собственное мероприятие. Одним из преимуществ использования свойства аргумента события является то, что все подписчики на событие могут видеть, что вернули предыдущие подписчики.

16
Don Kirkby

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

Создайте свой собственный класс обработчика событий

public class myCustomeEventArgs:EventArgs
{
    public bool DoOverride { get; set; }
    public string Variable1 { get; private set; }
    public string Variable2{ get; private set; }

    public myCustomeEventArgs(string variable1 , string variable2 )
    {
        DoOverride = false;
        Variable1 = variable1 ;
        Variables = variable2 ;
    }
}

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

public delegate void myCustomeEventHandler(object sender, myCustomeEventArgs e);

А в классе, поднимающем событие, вы объявляете это событие.

public event myCustomeEventHandler myCustomeEvent;

Поэтому, когда вы запускаете событие в своем классе, класс, который прослушивает событие, вы можете просто в теле события установить e.DoOverride = true; как это будет объявлено в классе, запускающем событие.

Событие пожара, например:

if(myCustomeEvent != null)
{
    var eventArgs = new myCustomeEventArgs("Some Variable", "Another Varaible");
    myCustomeEvent(this, eventArgs);
    //Here you can now with the return of the event work with the event args
    if(eventArgs.DoOverride)
    {
       //Do Something
    }
}
13
Riaan Swart

Примечание: только последнее событие возвращает результат.

class Program
{
static event Func<string, bool> TheEvent;

    static void Main(string[] args)
    {
        TheEvent += new Func<string, bool>(Program_TheEvent);
        TheEvent +=new Func<string,bool>(Program_TheEvent2);
        TheEvent += new Func<string, bool>(Program_TheEvent3);
        var r = TheEvent("s"); //r == flase (Program_TheEvent3)
    }

    static bool Program_TheEvent(string arg)
    {
        return true;
    }

    static bool Program_TheEvent2(string arg)
    {
        return true;
    }

    static bool Program_TheEvent3(string arg)
    {
        return false;
    }        
}
9
Alatey

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

   Func<DataRow, bool> IsDataValid;

   // some other code ....

   isValid = true;
   if (IsDataValid != null)
   {
      foreach (Func<DataRow, bool> func in IsDataValid.GetInvocationList())
      {
         isValid &= func(Row);
      } 
   }
8
Henk

Если событие возвращает значение и зарегистрировано несколько обработчиков, событие возвращает значение результата последнего вызванного обработчика. Ищите пример в http://blogs.msdn.com/b/deviations/archive/2008/11/27/event-handlers-returning-values.aspx

1
sammybar

Я зациклил свойства EventArgs вот так и вытащил их значения X и Y. 

private void navBarControl1_Click (отправитель объекта, EventArgs e) { int _x = 0; int _y = 0;

        Type t = e.GetType();
        IList<PropertyInfo> props = new List<PropertyInfo>(t.GetProperties());

        foreach (PropertyInfo prop in props)
        {
            if (prop.Name == "X")
            {
                object propValue = prop.GetValue(e, null);
                _x = Convert.ToInt32(propValue);
            }
            if (prop.Name == "Y")
            {
                object propValue = prop.GetValue(e, null);
                _y = Convert.ToInt32(propValue);
            }
        }
0
user1218233