views:

201

answers:

9

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

private void button1_Click(object sender, EventArgs e)

always void?

can it return any value too?

+1  A: 

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.

EAMann
Don't mix up VB and C#. There is no such thing as a sub routine in C#.
EricSchaefer
No there's not, but a function with a return type of void in C# serves the same purpose as a sub routine in VB. For someone who doesn't understand why a function would return void, this is the easiest explanation.
EAMann
+3  A: 

You can't do this because the delegate that handles the event is expecting a certain signature (you'll get compile error if you try and change it). For example the delegate in this case (Button.Click) is a System.EventHandler, it has to match that signature to compile/function as a delegate at all:

public delegate void EventHandler(Object sender, EventArgs e)

This is just how delegates work, when you look at how it's usually used, it makes more sense:

MyButton.Click += button1_Click;

If you returned anything else...what would it be used for? If you intend to call something that returns a result...that's what a method is for, not an EventHandler :)

Nick Craver
+1  A: 

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;
  }
}
Derick Bailey
+2  A: 

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.

Florian Reischl
This also only works for one the the subscribers of a multicast delegate, if I recall correctly.
EricSchaefer
@Eric: unless you use a custom raise implementation that calls each subscriber in turn. See `Delegate.GetInvocationList`.
Ben Voigt
But then it is not really a multicast delegate. Then you could use a subscriber collection (`List<EventWithReturnValue>`) or implement the observer pattern entirely manually and do without the syntactic sugar of events.
EricSchaefer
A: 

As a college professor of mine used to say about almost every question "It depends on the implementation". In this particular case, working with event handlers, there is nothing implicit with this model that would prevent and implementation of this pattern to return something back to the calling code. However, you're passed both the sender object as well as the originating event arguments, with basically form your executing environment context, there is no need to return anything since you can work directly with those references to achieve any relevant functionality.

Other frameworks may allow for an event handler to return something.

StudiousJoseph
+6  A: 

An event can have a return value. But it is a BCL guideline to return void (and have 2 parameters).

It becomes a bit murky when you use the multicast property of events, the returned value is the value of the last handler executed. The return of all other subscribed handlers is lost, and you don't have much control over the order in which they are executed. This makes a return value very impractical.

You could write:

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

class Program
{
    public event Summer OnSum;   // event

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

        int sum = OnSum(data);   // execute it.
    }
}
Henk Holterman
A nice comparison would be any global windows event handler, i.e. a keyboard or mouse hook, where return values are used to decide whether or not a next chained event handler should be called (which answers the "what would it be used for" question popping up in this thread). This principle is used in more environments and languages (JavaScript for one), but was removed from .NET in favor of clarity.
Abel
With `Delegate.GetInvocationList` you have total control over the order in which handlers are called and access to all the return values. But doing this is rather unusual.
Ben Voigt
+6  A: 

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.

Chris Taylor
+1 for putting result in the EventArgs.
Guffa
+1 for a short and lovely explanation
sumit_programmer
+4  A: 

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.

Thorarin
+1 for putting result in the EventArgs.
Guffa
+1  A: 

As a number of people have already stated this a convention not a constraint. You can have an event return things within the EventArgs itself. Microsoft uses this pattern in many places, see the FormClosing event in WinForms. So if you want to return a value do something like the following:

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

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

Knowing this now let's discuss why the designers chose the 'standard' void-return prototype of events:

  1. If they had a return value what type would it be?
  2. If the event returned a value, what would that value mean?
  3. By not having a return type, events can be one-directional. Meaning if I don't care about exceptions I can 'fire and forget' the event like calling Control.BeginInvoke(...)

Update: Ben rightfully adds: #4: what if an event needed to return more than one value?

csharptest.net
You forgot, "what if an event needed to return more than one value?"
Ben Voigt
Good catch Ben, thx.
csharptest.net