top of page
Writer's picturesantosh nalla

Delegates, Events, Actions, Func

Updated: Sep 15, 2021

DELEGATES:

Delegates and Events are usually super confusing. Here in this blog i will make them as simple as possible. Usually Delegates and Events are mostly of C# related concepts. UnityEvents are specific to Unity. Before discussing Unity Events , lets try to understand Delegates and Events.


Delegates are nothing but a variable that holds a method or several Methods.

We declare Delegate using the keyword "delegate" and then we give method signature.

public delegate function_return type Delegate_Type_Name(parameters if any) 
Ex: public Delegate void FunctionDelegate(int a)

Now to use Delegate we create a variable type "FunctionDelegate".

Ex: public FunctionDelegate delegateName;

Now i can assign delegateName to any functions that matches the above signature(void Func_Name(int a) )


In simple terms, the use of delegates is like subscription concept. All the methods that are subscribed to delegates are simply called by calling that delegate.

Suppose you created a delegate Del and subscribed the functions A(), B(),C() to our Delegate Del. so instead of calling:

A();

B();

C();

you can simply call Del().

So Del() = A(); AND B(); AND C(); 

A very important note here is what ever function you are subscribing, their signatures must match at the time of Delegate Creation.


Example Code:

Lets Create a Delegate D1 and subscribe 3 functions to it.

public class DelegatesAndEvents : MonoBehaviour
{

    //Declating a Delegate 
    public delegate void Delegate1();
    public Delegate1 D1;

    void Start()
    {
        //Subscribing methods(Multicasting) with similar signature to delegate D1
        D1 += A_D1;
        D1 += B_D1;
        D1 += C_D1;

        //Calling Delegate D1
        if(D1 != NULL) // very important to check this.
        D1();
    }


    void A_D1()
    {
        Debug.Log("A_D1 CALLED");
    }
    void B_D1()
    {
        Debug.Log("B_D1 CALLED");
    }
    void C_D1()
    {
        Debug.Log("C_D1 CALLED");
    }
}

OUTPUT: 
A_D1 CALLED
B_D1 CALLED
C_D1 CALLED

So if you see the above code, we usually subscribe to Delegate using += and then the method name.

To unsubscribe we use -=. Once you unsubscribe, that method is no longer part of that delegate.

In the above code if you note, by just calling D1(), All the functions which are subscribed to D1 are called(A_D1(), B_D1() and C_D1()). Calling D1 is equal to calling these 3 functions.


To can subscribe/unsubscribe any function to that delegate at any stage of your coding.


The process of subscribing more than 1 function to delegate is called Multicasting, we do that using +=.


One more important thing to note is, before calling delegate it is very important to check if it is not null, because if it is null, it throws an error.



EVENTS:

Events are specialized Delegates.They allow us to create a type of broadcast system that allows other classes and objects to subscribe/Desubscribe to our delegates.

Use of events is very similar to Delegates but yes there is one security difference which i am gonna explain later.


Declaring an event is very similar to Delegate. The only difference is you add event keyword

here.

Ex:    
    public delegate void ColorChange();
    public static event ColorChange colorChangeEvent;

For our example code, lets have 3 cubes and a "Control" script. On a button click we are gonna turn those 3 cubes black by using events(This can also be achieved using Delegates also so chill :P ).


Control Script:


public class ControlScript : MonoBehaviour
{
   //Declaring an event here
    public delegate void ColorChange();
    public static event ColorChange colorChangeEvent;

  //This function is called on button click
    public void onButtonClick()
    {
        if(colorChangeEvent != null)
        colorChangeEvent();  //Calling an event here
    }
}

Now this below script is attached to 3 cube game objects in our scene.

Each cube subscribes to the event declated in control script;

public class CubeColorChangeScript : MonoBehaviour
{
    private void Start()
    {
        ControlScript.colorChangeEvent += ColorChangeFunction;
    }

    void ColorChangeFunction()
    {
        transform.GetComponent<MeshRenderer>().material.color = new Color(0, 0, 0, 1);
    }
}

OUTPUT: on click of button each cube turns black!!!



So if you observe the above program, event "colorChangeEvent" doesn't even know that 3 cubes exist in the scene. So all the methods which needs to be called are subscribed to that event. Event simple calls all the methods which are subscribed to it.

THE SAME THING WHICH IS DONE ABOVE CAN ALSO BE DONE USING DELEGATE (LIKE JUST BY REMOVING "event" KEYWORD). Then what is the specialty of the event?


Let me explain this here - Events have inherit Security where as delegate variables doesn't.

If we use Delegate variables, other classes can invoke and Control Delegates execution - So no security here. But it doesn't happen in case of events. So events only allow classes to subscribe and unsubscribe functions, and doesn't allow actual invoking of events.


ACTIONS:

Actions are similar to events and delegates - but instead of using 2 lines of code (one for delegate and one for event) we can use one line of code.


So instead of using:

  public delegate void D1(int n, string s);
  public event D1 D_event;

we can just write:

using System;
.
.
public Action<int,string> D_event;

So, the thing to note here is, Actions basically cannot have any return type. Actions can be used for function signatures which have parameters but no return type


Example:

Lets say i have 2 actions - ActionWithParameters and ActionWithoutParameters in an ActionDemo script. We have 2 subscribers which subscribe to this action. I am gonna paste this script below which is self explanatory. You can copy paste this scripts into your project and test them out.



using System;
using UnityEngine;

public class ActionsDemo : MonoBehaviour
{
    [SerializeField]
    private bool triggerActionWithParameter = false;
    [SerializeField]
    private bool triggerActionWithOutParameter = false;

    public static Action ActionWithOutParameter;
    public static Action<string, int> ActionWithParameter;


    private void Update()
    {
        if (triggerActionWithParameter)
        {
            ActionWithParameter?.Invoke("Hello", 3);
            triggerActionWithParameter = false;
        }

        else if (triggerActionWithOutParameter)
        {
            ActionWithOutParameter?.Invoke();
            triggerActionWithOutParameter = false;
        }
    }
}

Subscriber 1:

using UnityEngine;

public class ActionSubscriber1 : MonoBehaviour
{
    void Start()
    {
        ActionsDemo.ActionWithOutParameter += Function1_WithoutParameter;
        ActionsDemo.ActionWithParameter += Function1_WithParameter;
    }

    void Function1_WithoutParameter()
    {
        Debug.Log("Function1 without parameter");
    }

    void Function1_WithParameter(string parameter, int number)
    {
        Debug.Log("Function1 with parameter: " + parameter + number);
    }
}

Subscriber 2:

using UnityEngine;

public class ActionSubscriber2 : MonoBehaviour
{
   
    void Start()
    {
        ActionsDemo.ActionWithOutParameter += Function2_WithoutParameter;
        ActionsDemo.ActionWithParameter += Function2_WithParameter;
    }

    void Function2_WithoutParameter()
    {
        Debug.Log("Function2 without parameter");
    }

    void Function2_WithParameter(string parameter, int number)
    {
        Debug.Log("Function2 with parameter: " + parameter + number);
    }
}


output when "triggerActionWithParameter" is enabled:

Function1 without parameter

Function2 without parameter


output when "triggerActionWithParameter" is enabled:

Function1 with parameter: Hello3

Function2 with parameter: Hello3


In practical use, you find people using Lambda expression when they are using Actions.

Lambda expressions essentially allow us to write methods in line.

we using use lambda expression with below format:

() => { ....... };


let take a simple action to calculate sum of 2 numbers:


using System;
using UnityEngine;

public class ActionsUsingLambdaExpression : MonoBehaviour
{
    Action<int, int> Action_CalculateSum; 
    void Start()
    {
        //Subscribing
        Action_CalculateSum += CalculateSum;

        //Invoking
        Action_CalculateSum?.Invoke(4, 5);
    }

    void CalculateSum(int a, int b)
    {
        int c = a + b;
        Debug.Log("Sum is: " + c);
    }
}

This is how you do, if we dont use lambda expression.

Now lets use lambda expression and make it simple.


using System;

using UnityEngine;



public class ActionsUsingLambdaExpression : MonoBehaviour
{
    Action<int, int> Action_CalculateSum; 
    void Start()
    {
        //Subscribing with out lambda expression
        //Action_CalculateSum += CalculateSum;

        //Subscribing with lambda expression
        Action_CalculateSum += (a,b) => {
                                            int c = a + b;
                                            Debug.Log("Sum is: " + c);
                                        };

        //Invoking
        Action_CalculateSum?.Invoke(4, 5);
    }
}

This is how we use lambda expressions for actions.




75 views0 comments

Recent Posts

See All

Asynchronous Programming in Unity

Most Unity Developers might be aware of the concept of Asynchronous Programming - if “Coroutines” are what came into your mind, yes, that...

Extension Methods in Unity

Lets say you want to add a function to Transform class called Reset() - which resets position, Rotation and Scale values of a particular...

LINQ - C# in Unity Game Programing

LINQ stands for Language Integrated Query. Basically this is used/allows us to filter through data(arrays and lists). Data filtering on...

Comments


bottom of page