为什么事件处理程序总是有返回类型的void?

smr*_*iti 25 .net c# events event-handling

嘿,我想知道为什么返回类型的事件如

private void button1_Click(object sender, EventArgs e)
Run Code Online (Sandbox Code Playgroud)

永远无效?

它还可以返回任何其他值吗?

Chr*_*lor 34

事件处理程序签名,即返回类型以及它所采用的参数的数量和类型,由delegate用于定义事件的签名确定.因此,示例中Button的Click事件不支持任何返回值.

通常,您不希望从事件处理程序返回值作为函数返回值,因为事件可以有多个订阅者,并且每个都将返回独立于其他处理程序的返回值,并且需要特殊事件触发代码来决定处理所有返回值.

通常,如果您需要从事件处理程序进行通信,则EventArgs结构将包含处理程序可以更新的成员,并且每个处理程序将获得查看值并相应更新的机制,并且触发事件的代码只需要响应结构中的最终值.


Hen*_*man 17

事件可以具有返回值.但它是返回void的BCL指南(并且有2个参数).

使用事件的多播属性时,返回值会变得有点混乱.返回的值是最后执行的处理程序的值.所有其他订阅处理程序的返回都将丢失,并且由于事件用于解耦,因此您无法控制它们的执行顺序.这使得返回值非常不切实际.

另一种BCL实践是通过EventArgs后代的可写属性共享和返回信息,例如CancelWindow.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.
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 一个很好的比较将是任何全局Windows事件处理程序,即键盘或鼠标钩子,其中返回值用于决定是否应该调用下一个链式事件处理程序(它回答"它将用于什么"问题弹出在这个线程中).此原则用于更多环境和语言(JavaScript for one),但已从.NET中删除,以支持清晰度. (2认同)

Tho*_*rin 9

除了.NET期望标准控件中事件的某个签名这一事实之外,请考虑以下事项:事件可以附加多个事件处理程序,其中一个返回值将被使用?

事件处理程序返回值只是没有意义.通常,它们将修改某些对象的状态,EventArgs以便将某些内容传回给触发事件的内容.


Yog*_*esh 6

在c#中,Events可以有两种类型

1.组播
2. UnitCast

多播事件是指具有多个订户的事件.当引发多播事件时,将调用多个处理程序,因为您已订阅了多个事件处理程序. 那么,多播事件是用来调用多个处理程序而多播处理程序不能有返回类型为什么?

因为如果多播委托具有返回类型,则每个事件处理程序都将返回一些值,并且一个事件处理程序的返回值将被下一个事件处理程序值替换.

假设您有一个多播委托如下

public delegate int buttonClick;

public event buttonClick onClick;

onClick += method1
onclick += method2
onclick += metho3
Run Code Online (Sandbox Code Playgroud)

当引发此事件时,method1返回的值将被method2返回的值替换,最终将只接收method3的值.

因此,在Multicast委托的情况下,始终建议不要返回任何值.

但是在unicast deleagte的情况下,你只有一个用户.因此,您可以返回价值以实现您的目的

因此,对于多播委托 - 无返回类型和单播委托 - 可以具有返回类型

多播委托也可以返回多个值,但必须手动引发该事件.

如果您选择多播委托也应该返回值的事件,假设我有一个绑定到4事件处理程序的事件,它需要两个整数,一个处理程序添加,第二个减法和第三个乘法和最后一个除法.因此,如果要获取所有处理程序的返回类型,则必须以下列方式手动引发事件,

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

}
Run Code Online (Sandbox Code Playgroud)


Nic*_*ver 5

你不能这样做,因为处理事件的委托期望某个签名(如果你尝试更改它,你会得到编译错误).例如,在这种情况下(Button.Click)的委托是a System.EventHandler,它必须匹配该签名以编译/作为委托作用:

public delegate void EventHandler(Object sender, EventArgs e)
Run Code Online (Sandbox Code Playgroud)

这就是代表的工作方式,当你看看它通常如何使用时,它更有意义:

MyButton.Click += button1_Click;
Run Code Online (Sandbox Code Playgroud)

如果你还没有其他任何东西......它将被用于什么?如果你打算调用返回结果的东西......这就是方法的用途,而不是EventHandler :)


Flo*_*chl 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;
      }
   }
Run Code Online (Sandbox Code Playgroud)

但是,使用事件返回值在组件及其使用者之间交换信息并不常见.


EAM*_*ann 1

返回类型为 void,因为它是子例程,而不是函数。您可以让它返回一个值,但事件处理程序(这就是挂接到按钮单击事件的子例程)并不完全是有意的。

在 VB 中,这行代码为:

Private Sub button_Click(ByVal sender As Object, ByVal e As EventArgs)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,VB 中显式的“Sub”语句更有意义,但请记住,voidC# 中的所有 s 只是子例程...它们根据参数在代码中执行某些操作,但不返回值。但是,他们可以更改传入参数的值。