Почему обработчики событий всегда имеют тип возврата пустоты?

Эй, я задался вопросом, почему случается так что тип возврата событий такой как

private void button1_Click(object sender, EventArgs e)

является всегда пустым?

Это может возвратить какое-либо другое значение также?

25
задан Edward Karak 25 January 2014 в 17:49
поделиться

9 ответов

Сигнатура обработчика события, то есть тип возврата и количество и типы принимаемых аргументов, определяется сигнатурой делегата, используемого для определения события. Поэтому событие Click кнопки Button в вашем примере не поддерживает никаких возвращаемых значений.

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

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

34
ответ дан 28 November 2019 в 17:52
поделиться

Событие может иметь возвращаемое значение. Но согласно рекомендациям BCL возвращать значение void (и иметь 2 параметра).

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

Другой практикой BCL является обмен и возврат информации через записываемое свойство потомка EventArgs, например, свойство Cancel события Window.Closing. Все обработчики могут видеть и изменять его. Это все еще последнее беспроигрышное решение, но уже лучше.

Но, сказав все это, вы все равно можете написать:

delegate int Summer(int[] arr);  // delegate

class Program
{
    public event Summer OnSum;   // event

    void DoSum()
    {
        int[] data = {1, 2, 3} ;              
        int sum = 0;

        if (OnSum != null)  
          sum = OnSum(data);   // execute it.
    }
}
17
ответ дан 28 November 2019 в 17:52
поделиться

Вы не можете этого сделать, потому что делегат, обрабатывающий событие, ожидает определенной подписи (вы получите ошибку компиляции, если попытаетесь ее изменить). Например, делегат в этом случае ( Button.Click ) - это System.EventHandler , он должен соответствовать этой сигнатуре для компиляции / работы в качестве делегата вообще:

public delegate void EventHandler(Object sender, EventArgs e)

Это Именно так работают делегаты, когда вы посмотрите на то, как они обычно используются, это приобретает больше смысла:

MyButton.Click += button1_Click;

Если бы вы вернули что-нибудь еще ... для чего это было бы? Если вы собираетесь вызвать что-то, что возвращает результат ... для этого нужен метод, а не EventHandler :)

5
ответ дан 28 November 2019 в 17:52
поделиться

Конечно, события могут возвращать значения.

   [TestClass]
   public class UnitTest1 {
      delegate int EventWithReturnValue();

      class A {
         public event EventWithReturnValue SomeEvent;
         public int LastEventResult { get; set; }

         public void RaiseEvent() {
            LastEventResult = SomeEvent();
         }
      }

      [TestMethod]
      public void TestMethod1() {
         A a = new A();
         a.SomeEvent += new EventWithReturnValue(a_SomeEvent);
         a.RaiseEvent();
         Assert.AreEqual(123, a.LastEventResult);
      }

      int a_SomeEvent() {
         return 123;
      }
   }

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

5
ответ дан 28 November 2019 в 17:52
поделиться

Как уже было сказано рядом людей, это соглашение, а не ограничение. Вы можете сделать так, чтобы событие возвращало вещи в самом EventArgs. Microsoft использует этот шаблон во многих местах, см. Событие FormClosing в WinForms. Итак, если вы хотите вернуть значение, сделайте что-то вроде следующего:

public class AllowCloseEventArgs : EventArgs
{
    public bool AllowClose = true;
}

public void AllowClose(object sender, AllowCloseEventArgs e)
{ e.AllowClose = false; }

Теперь, зная это, давайте обсудим, почему дизайнеры выбрали «стандартный» прототип событий с возвратом пустоты:

  1. Если бы у них было возвращаемое значение, какой тип он бы выбрал? быть?
  2. Если событие вернуло значение, что это значение будет означать?
  3. Не имея возвращаемого типа, события могут быть однонаправленными. Это означает, что если меня не волнуют исключения, я могу «запустить и забыть» событие, например вызвать Control.BeginInvoke (...)

Обновление: Бен справедливо добавляет: №4: что, если событие должно возвращать более одного значения?

3
ответ дан 28 November 2019 в 17:52
поделиться

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

public class AnEvent
{
  public delegate MyReturnType MyDelegateName();
  public event MyDelegateName MyEvent;

  public void DoStuff()
  {
    MyReturnType result = null;
    if (MyEvent != null)
      result = MyEvent();
    Console.WriteLine("the event was fired");
    if (result != null)
      Console.Writeline("the result is" + result.ToString());
  }
}

public class EventListener
{
  public EventListener()
  {
    var anEvent = new AnEvent();
    anEvent.MyEvent += SomeMethod;
  }

  public MyReturnType SomeMethod()
  {
    Console.Writeline("the event was handled!");
    return new MyReturnType;
  }
}
3
ответ дан 28 November 2019 в 17:52
поделиться

Тип возврата - void, потому что это подпрограмма, а не функция. Вы могли бы заставить ее вернуть значение, но обработчики событий (чем и является подпрограмма, подключенная к событию нажатия кнопки) не совсем для этого предназначены.

В VB эта строка кода была бы:

Private Sub button_Click(ByVal sender As Object, ByVal e As EventArgs)

Явный оператор "Sub" в VB имеет немного больше смысла в этом случае, но помните, что все voidы в C# - это просто подпрограммы... они делают что-то в коде на основе аргументов, но не возвращают значение. Однако они могут изменять значения переданных аргументов.

1
ответ дан 28 November 2019 в 17:52
поделиться

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

Другие фреймворки могут позволять обработчику событий возвращать что-либо.

0
ответ дан 28 November 2019 в 17:52
поделиться

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

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

9
ответ дан 28 November 2019 в 17:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: