0
\$\begingroup\$

If my button uses AddListener to subscribe a function to listen for clicks:

mybutton.onClick.AddListener(getNameFunction);

Is there a way to get the name of that listening function (i.e. "getNameFunction" in this example)?

I tried onClick.GetPersistentMethodName(0), but it does not seem like the right way.

if i add funtcion in onclick list, .GetPersistentMethodName(0) will return the name

enter image description here

But it does not seem to return the correct result when the function was added using AddListener in the script (e.g. in Start())."

\$\endgroup\$
1
  • 1
    \$\begingroup\$ this sounds like an XY problem to me. Can you tell us why you need the name of the event handler method? Perhaps there is a better way to accomplish what you are actually trying to achieve. \$\endgroup\$
    – Philipp
    Commented Mar 14, 2023 at 12:01

2 Answers 2

2
\$\begingroup\$

The problem is, you are using the normal AddListener method when adding your function. Listeners that you add over the editor do not use AddListener but AddPersistentListener.

As you can already see from the name, it matches the GetPersistentMethodName. GetPersistentEventCount returns as well 0 for the normal AddListener. You need to change the way how you add it since it is not possible to do it exactly the same way. Luckily there is a tool helper class for it.

public Button button;

void Start() {
    UnityEventTools.AddPersistentListener(button.onClick, MyClickFunction);
}

public void MyClickFunction() {
    Debug.Log(button.onClick.GetPersistentMethodName(0));
}

UnityEventTools is in the UnityEditor namespace and can't be used in the compiled build. Depending on why and for what you need the method name and the option in the editor compared to the normal listener, where you actually include the UnityEventTools.AddPersistentListener will depend. But you can't leave it in Start for your compiled build.

Normal editor Editor coding

Runtime: Runtime

\$\endgroup\$
0
3
\$\begingroup\$

I felt fancy and decided to answer the actual question. You can do that with some reflection:

using System;
using System.Collections;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.Events;

public class GettingMethodNamesFromUnityEvent : MonoBehaviour
{
    public UnityEvent exampleEvent;

    void Start()
    {
        exampleEvent.AddListener(Foo);
        exampleEvent.AddListener(Bar);
        exampleEvent.AddListener(Baz);

        var mCalls = exampleEvent
            .GetType()
            .BaseType
            .GetField("m_Calls", BindingFlags.NonPublic | BindingFlags.Instance)
            .GetValue(exampleEvent);

        var mRuntimeCalls = mCalls
            .GetType()
            .GetField("m_RuntimeCalls", BindingFlags.NonPublic | BindingFlags.Instance)
            .GetValue(mCalls) as IList;

        var delegateField = mRuntimeCalls[0]
            .GetType()
            .GetField("Delegate", BindingFlags.NonPublic | BindingFlags.Instance);

        var methodNames = mRuntimeCalls
            .Cast<object>()
            .Select(runtimeCall => delegateField.GetValue(runtimeCall))
            .Cast<MulticastDelegate>()
            .SelectMany(mcDel => mcDel.GetInvocationList())
            .Select(del => del.Method.Name)
            .ToArray();

        Debug.Log(string.Join(", ", methodNames));
    }

    private void Foo()
    {
    }

    private void Bar()
    {
    }

    private void Baz()
    {
    }
}

Prints "Foo, Bar, Baz" as expected:

enter image description here

Please note that this is terrible code, and you should probably never ever use it.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .