Search Unity

How is UnityAction different from .NET's built-in Action?

Discussion in 'Scripting' started by casimps1, Jan 3, 2015.

  1. casimps1

    casimps1

    Joined:
    Jul 28, 2012
    Posts:
    254
    As I've been getting up to speed on 4.6 I've noticed the new event system and specifically the UnityAction delegates. I also know that .NET has had built-in delegates called Actions that seem to be almost exactly the same and I've been using them in Unity for some time now:

    http://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx

    The only difference I've been able to see so far is that UnityAction is limited to 4 parameters, whereas .NET's Action goes up to 16.

    Is there a reason to use UnityAction over .NET's built-in Action?
     
    rakkarage likes this.
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    No particular reason, other than if you're working with the unity events system. Even though they're shaped the same, you can't coerce a delegate created as an Action into a UnityAction, or vice versa...
     
    mandisaw and IgorAherne like this.
  3. cmcpasserby

    cmcpasserby

    Joined:
    Jul 18, 2014
    Posts:
    315
    Really the main bit about UnityEvent and UnityAction that is useful is that they are searlized by the unity inspector, and you can assign the object and method to notify via drag and drop on the inspector.
     
  4. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    That's my understanding. Useful for telling a game object what to do, in the Inspector, instead of subclassing, or getting a reference to a scriptable object. It's clean, unless the delegate needs to change.
     
  5. cmcpasserby

    cmcpasserby

    Joined:
    Jul 18, 2014
    Posts:
    315
    Ya I use a mix of both, based on what I need at a time. I will use the built in C# ones if I just want to subscribe and tell it what method to use in code. Than I will use UnityEvent if I want to pass this information in via the inspector.
     
    yulun2012 likes this.
  6. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    It's worth mentioning here that even if you use System.Action you're still limited to 4 parameters, cause you're not using .NET's Action, but Unity Mono's
     
    isma_sch and casimps1 like this.
  7. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    A thing to look out for when using Unity's delegates, is that if you add a listener (via code) in-editor (i.e. in edit time), for some reason it doesn't get added, it could be that I'm missing something, or a bug. Here's a video. I made a thread about it in the past, no response. I ended up just using my custom delegates
     
    Inannani likes this.
  8. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    That's not true. Delegates can be namespace-level, so you can copy and paste from the MSDN until Unity gets with the program.
    Code (CSharp):
    1. namespace System {
    2.     public delegate void Action<in T1, in T2, in T3, in T4, in T5>(
    3.         T1 arg1,
    4.         T2 arg2,
    5.         T3 arg3,
    6.         T4 arg4,
    7.         T5 arg5
    8.     );
    9. }
    I don't actually recommend this. You should use structs instead, until Microsoft also gets with the program and introduces tuples with named parameters like in Swift.
     
  9. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @Jessy I'm talking about when you don't do what you did. i.e. just going with what comes with Unity's mono which only allows 4 args

     
  10. casimps1

    casimps1

    Joined:
    Jul 28, 2012
    Posts:
    254
    I've noticed something similar. When I first started playing with the event system I tried adding a listener via code (at runtime) and then looking in the inspector to see if it showed anything, but it doesn't. After digging a little more, the conclusion I came to was that there are actually two types of listeners, regular listeners and persistent listeners. Both of them get called when the event triggers, but under the hood, they're different.

    Regular listeners are added via the AddListener call in code. They add a simple zero-parameter delegate (UnityAction) callback. They are not serialized. They cannot be accessed via the inspector (even the debug inspector).

    Persistent listeners are added via the inspector. They specify the GameObject, the method, and the parameters to be sent to that method. They are serialized. They cannot be accessed via code.

    I originally wanted access to the persistent listener interface in code so that I could send some parameters along rather than being forced into calling a zero-parameter method... but I ended up using a lambda expression instead which actually works nicely without getting too messy. So, if I wanted to add a listener to the onClick of a Button that would call a ButtonPressed method with the int ID of that button, then I do this:

    Code (CSharp):
    1. onClick.AddListener( () => ButtonPressed( buttonID ) );
    To make a call to a method on another GameObject it would just be:

    Code (CSharp):
    1. onClick.AddListener( () => someGameObj.SendMessage( someParam ) );
    or even better, if I had a reference to the instance of the Component I want on that other GameObject:

    Code (CSharp):
    1. onClick.AddListener( () => someComponent.SomeMethod( someParam ) );
    So, you can basically do the same thing that persistent listeners do just by using regular listeners and lambda expressions.

    Still, for your use case (adding listeners at design time), it would be nice to have code access to the persistent listeners.
     
    tcz8, Olipool, yulun2012 and 4 others like this.
  11. casimps1

    casimps1

    Joined:
    Jul 28, 2012
    Posts:
    254
    Aha! So I found out there is a way to add persistent listeners via code at design time: Check out UnityEventTools:

    http://docs.unity3d.com/460/Documentation/ScriptReference/Events.UnityEventTools.html
     
    Inannani and Seneral like this.
  12. Novack

    Novack

    Joined:
    Oct 28, 2009
    Posts:
    844
    Something I think is relevant when considering what event system to use, is builds stripping levels.

    From a mono compatibility standpoint, would be better to use UnityEngine.Events over System.Action, given that in some mscorlib profiles the later is not inluded ("micro" .net profile).
     
    Last edited: Apr 30, 2020
    YutaSuzuki likes this.
  13. MV10

    MV10

    Joined:
    Nov 6, 2015
    Posts:
    1,889
    Not to hijack the thread (I came here wondering about .NET Action / UnityAction differences too) but:

    I've been wondering about this ever since I saw a link to the stripping list a few weeks ago. Does it make any sense to use Unity on any of the limited hardware targeted by the .NET micro framework? Are any of these CPUs even targeted by Unity?

    https://en.wikipedia.org/wiki/.NET_Micro_Framework#Hardware

    I've done a fair bit of duino work (and we even own two or three of the cool but poorly-supported Netdunios) and it would have never occurred to me to burn storage, RAM, or clocks on Unity-level overhead.
     
  14. SubZeroGaming

    SubZeroGaming

    Joined:
    Mar 4, 2013
    Posts:
    1,008
    JoeStrout likes this.
  15. MV10

    MV10

    Joined:
    Nov 6, 2015
    Posts:
    1,889
    Since it turns out that event AddListener only accepts UnityAction refs, it's sort of a moot question in my case (I prefer to standardize on just one or the other in a project).
     
    Erethan likes this.
  16. tcz8

    tcz8

    Joined:
    Aug 20, 2015
    Posts:
    504
    Still useful 6 years later! Thank you.