Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Events, what's best between events + delegate, event + EventHandler etc.

Discussion in 'Scripting' started by Kiupe, May 24, 2016.

  1. Kiupe

    Kiupe

    Joined:
    Feb 1, 2013
    Posts:
    528
    Hi guys,

    What's the difference and the best approach when it comes to event in C# ? According to the documentation there is several ways to do it : https://msdn.microsoft.com/en-us/library/edzehd2t(v=vs.110).aspx

    What do you use and why ?

    - Event + EventHandler
    - Event + Delegate
    - Event + Action

    Really curious to know your choices and reasons !

    Thanks
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,376
    Well, all of those are technically delegates.

    Here's the thing, all 'event' does is act as an access modifier for delegate fields. It basically states that all code outside the scope of the declaring code can only add or remove handlers, and only owner scoped code can call or destroy it.

    It can be used with ALL delegate types, as it's just a access modifier for delegates.

    Code (csharp):
    1.  
    2. public class Foo
    3. {
    4.     public Action action;
    5. }
    6.  
    7. public class Bar
    8. {
    9.     public event Action action;
    10. }
    11.  
    12. var obj = new Foo();
    13. obj.action = new Action(SomeFunc); //legal code
    14. obj.action(); //legal code
    15.  
    16. var obj2 = new Bar();
    17. obj.action = new Action(SomeFunc); //illegal code
    18. obj.action(); //illegal code
    19.  
    The .Net standard suggests that events should always follow the 'EventHandler' shape, or some derivative there of. That being a shape of:

    Code (csharp):
    1.  
    2. EventHandler(object sender, EventArgs event)
    3. //or:
    4. EventHandlerDerivative(object sender, SubTypeOfEventArgs e)
    5.  
    Though it's still legal to use any other delegate type.

    I personally stick to the EventHandler so that events are interchangeable. As long as my handler is shaped like EventHandler I can register to ANY event (as long as it followed the standard). The reason it has the 'sender' and 'event' parameters is so that way you can send pertinent information to the handler while not breaking the shape of the delegate!

    Where as with 'Action' if you want to include some extra info, you'll end up having 'Action<ParameterType>', meaning the shape is not ubiquitous... I can't arbitrarily register for events.
     
  3. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,521
    There's also UnityEvents. They have a small amount of overhead, but they're built into Unity, they're extremely flexible, and they allow you to hook up events in the inspector without having to write additional code.
     
    Kiwasi likes this.
  4. Kiupe

    Kiupe

    Joined:
    Feb 1, 2013
    Posts:
    528
    Thanks for you answers guys, it's a bit clearer for me now !
     
  5. Kiupe

    Kiupe

    Joined:
    Feb 1, 2013
    Posts:
    528
    What do you mean that events are interchangeable ? If I need to send a SubTypeOfEventArgs like in the second case, how could you stick with EventHandler(object sender, EventArgs event) ? Do you simply then cast the EventArgs to SubTypeOfEventArgs ?

    Thanks
     
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,376
    Because SubTypeOfEventArgs inherits from EventArgs, it can be passed to a function that accepts only EventArgs.

    Code (csharp):
    1.  
    2. public class ExampleEventArgs : EventArgs
    3. {
    4.     public string Value;
    5. }
    6.  
    7. public class Example
    8. {
    9.     public event EventHandler<ExampleEventArgs> OnFoo;
    10.     public event EventHandler OnBar;
    11.  
    12.     public void DoFoo()
    13.     {
    14.         if(this.OnFoo != null) this.OnFoo(this, new ExampleEventArgs() {
    15.                 Value = "BLARGH"
    16.             });
    17.     }
    18.  
    19.     public void DoBar()
    20.     {
    21.         if(this.OnBar != null) this.OnBar(this, EventArgs.Empty);
    22.     }
    23. }
    24.  
    25.  
    26. public class TestExample
    27. {
    28.  
    29.     private Example _obj;
    30.  
    31.     public TestExample()
    32.     {
    33.         _obj = new Example();
    34.         _obj.OnFoo += this.OnSomething;
    35.         _obj.OnBar += this.OnSomething;
    36.     }
    37.  
    38.     private void OnSomething(object sender, EventArgs e)
    39.     {
    40.         //can't access e.Value... but we can react to OnSomething
    41.         Console.WriteLine("Something happened");
    42.  
    43.         //BUT, if we really did want to access it:
    44.         if(e is FooEventArgs)
    45.         {
    46.             Console.WriteLine("And it was: " + (e as ExampleEventArgs).Value)
    47.         }
    48.     }
    49.  
    50. }
    51.  
    In this example, 'OnSomething' can handle both OnFoo and OnBar because it accepts EventArgs. The shape (object, EventArgs) satisfies the shape of both due to polymorphism.

    But in the 'OnSomething' handler, if I want to know which one occurred, I have to do some extra testing.
     
    tealm and greatastrocow like this.