Why do event handlers always have a return type of void?

前端 未结 11 2062
夕颜
夕颜 2020-12-05 23:30

Hey, I wondered why is it that the return type of events such as

private void button1_Click(object sender, EventArgs e)

is always void?

相关标签:
11条回答
  • 2020-12-06 00:01

    introductory note: If the [single] method you want to call is on the same or lower dependency level as your calling code, then you can just go ahead and call it, there will be no need for events. So; events are only useful when at least one of your event raises (calls) is going to call a method from a layer above.

    Now, long answer depends on whether you write your own delegate and marking it as an event (1) or use EventHandler (2):

    1. If writing your own delegate, you could just have return the result you need. The problem though is that with multicast delegates only the result of the final subscribed method is returned.
    
    
        public class TestEvents
        {
            public event SomethingHappenedHandler1 SomethingHappened1;
            public event EventHandler SomethingHappened2;
        
            public void Run()
            {
                SomethingHappened1 += Scenario_DelegateOnly.SubscriberMethod;
                SomethingHappened1(this, 13, 15);
        
                SomethingHappened2 += Scenario_EventHandlerAndEventArgs.SubscriberMethod;
                SomethingHappened2(this, new MyEventArgs2(33, 35));
            }
        }
        
        //1
        public delegate int SomethingHappenedHandler1(object sender, int arg1, int arg2);
        public static class Scenario_DelegateCanHaveReturnValue
        {
            public static int SubscriberMethod(object sender, int arg1, int arg2)
            {
                Console.WriteLine($"{sender.ToString()} {arg1} {arg2} ... returning {arg1} * {arg2}");
                return arg1 * arg2;
            }
        }
        
        //2
        public static class Scenario_EventHandlerAndEventArgs
        {
            public static void SubscriberMethod(object sender, MyEventArgs2 args)
            {
                Console.WriteLine($"{sender.ToString()} {args.arg1} {args.arg2}");
            }
        }
        public class MyEventArgs2 : EventArgs
        {
            public MyEventArgs2(int arg1, int arg2)
            {
                this.arg1 = arg1;
                this.arg2 = arg2;
            }
            public int arg1;
            public int arg2;
        }
    
    
    1. If using EventHandler signature of your method return type will always be "void". Most often event raises are fire and forget operations (such as button_Click) and we might not care about results of operation, but when we do need some feedback, there is always a workaround because subscriber method can save those results to a property on the publisher; it just has to cast "sender" object to get an instance of publisher [which should be no problem unless subscriber is below the publisher in dependency (scenario noted where we did not need events to begin with!)].
    0 讨论(0)
  • 2020-12-06 00:02

    Aside from the fact that .NET expects a certain signature for the events in standard controls, consider this: an event can have multiple event handlers attached, which one of the return values would be used?

    It just doesn't make sense for event handlers to return a value. Typically, they will modify the state of some object that derives from EventArgs to communicate something back to whatever fired the event.

    0 讨论(0)
  • 2020-12-06 00:03

    An event handler signature, that is the return type and the number and types of arguments it takes, is determined by the signature of the delegate used to define the event. So the Click event of the Button in your example does not support any return values.

    Typically you would not expect to return a value from an event handler as a function return value because an event can have multiple subscribers and each would be returning a return value independently of the other other handlers and would require special event firing code to decide what to do with all the return values.

    Typically, if you need to communicate back from an event handler the EventArgs structure would contain members that the handler can update and each handler will get an oppertunity to look at the values and update accordingly, and the code firing the event only needs to react to the final value in the structure.

    0 讨论(0)
  • 2020-12-06 00:03

    the default EventHandler delegate defined this signature. However, you are free to create your own events with your own return types if you wish.

    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;
      }
    }
    
    0 讨论(0)
  • 2020-12-06 00:03

    The return type is void because it's a sub routine, not a function. You could have it return a value, but event handlers (which is what a sub routine hooked to a button click event is) aren't exactly intended to.

    In VB, this line of code would be:

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

    The explicit "Sub" statement in VB makes a little more sense in this case, but remember, all voids in C# are just subroutines ... they do something in the code based on arguments but don't return a value. They can, however, change the values of the arguments passed in.

    0 讨论(0)
  • 2020-12-06 00:13

    For sure, events can return values.

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

    However, it's not very common to use events return value to exchange information between components and their consumers.

    0 讨论(0)
提交回复
热议问题