Подтвердить что ты не робот

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

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

private void button1_Click(object sender, EventArgs e)

всегда недействителен?

Может ли он вернуть любое другое значение?

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Еще одна практика 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.
    }
}

Ответ 3

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

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

Ответ 4

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

public delegate void EventHandler(Object sender, EventArgs e)

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

MyButton.Click += button1_Click;

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

Ответ 5

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

   [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;
      }
   }

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

Ответ 6

В С# события могут быть двух типов

1. Multicast
2. UnitCast

Многоадресное событие - это те, у кого более одного подписчика. когда возникает событие многоадресной рассылки, тогда будет вызываться несколько обработчиков, поскольку вы подписали более одного обработчика событий. Итак, событие многоадресной рассылки предназначено для использования для вызова нескольких обработчиков, а обработчик многоадресной рассылки не может иметь тип возврата, почему?

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

предположим, что у вас есть многоадресный делегат, как показано ниже

public delegate int buttonClick;

public event buttonClick onClick;

onClick += method1
onclick += method2
onclick += metho3

когда это событие будет поднято, значение, возвращаемое методом1, будет заменено возвратом значения методом method2, и в итоге будет получено значение только метода 3.

Поэтому в случае делегата Multicast всегда рекомендуется не возвращать какое-либо значение.

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

Итак, для многоадресного делегата - тип возврата отсутствует и для одноадресного делегата - может иметь тип возврата

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

Событие в случае, если вы решите, что делегат многоадресной передачи также должен возвращать значения, скажем, что у меня есть событие, которое связано с 4-х обработчиком событий, и оно принимает два целых числа, а один обработчик добавляет, второе вычитание и третье умножение и последний деление. Итак, если вы хотите получить возвращаемый тип всех обработчиков, тогда вам нужно поднять событие вручную следующим образом:

var handler = _eventToRaised.GetInvocationList();
foreach(var handler in handlers)
{
  if(handler != null)
   {
    var returnValue = handler()// pass the values which delegate expects.
   }

}

Ответ 7

делегат 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;
  }
}

Ответ 8

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

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

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

Зная это, теперь обсудим, почему дизайнеры выбрали "стандартный" прототип void-return событий:

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

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

Ответ 9

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

В VB эта строка кода будет:

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

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

Ответ 10

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

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