Generic function to add listener method to dynamically selected static events.

I have this generic class which defines a static event Click

using UnityEngine;
using System;
using UnityEngine.EventSystems;

public class ClickButtonGeneric<T>: MonoBehaviour,IPointerClickHandler where T : class
{
    public static event Action Click;

    public void OnPointerClick(PointerEventData eventData)
    {
        ClickButton();
    }

    protected virtual void ClickButton()
    {
        Click.Invoke();
    }
   
}

This allows me to create various classes that inherit the generic class and have their own static event Click:

public class ClickButtonOptions : ClickButtonGeneric<ClickButtonOptions>{}
public class ClickButtonLogin : ClickButtonGeneric<ClickButtonLogin>{}

I, then can add methods as listeners of the event, like the following example:

using UnityEngine;

public class Options :MonoBehaviour
{
   
    private void Start()
    {
        ClickButtonOptions.Click += Toggle;
    }

    private void Toggle()
    {
        EventsManager.OnTogglePanel(GetComponent<CanvasGroup>());
    }

    private void OnDisable()
    {
        ClickButtonOptions.Click -= Toggle;
    }
   
}

I want to make a generic version of the above code where I will be able to define to which static event the Toggle method will be added. Something like the following:

using UnityEngine;

public class ToggleablePanel<T> :MonoBehaviour
{
   
    private void Start()
    {
        T.Click += Toggle;
    }

    private void Toggle()
    {
        EventsManager.OnTogglePanel(GetComponent<CanvasGroup>());
    }

    private void OnDisable()
    {
        T.Click -= Toggle;
    }
   
}

Is something like that possible?
Would another approach be better?

I’m not sure what the generic is even adding here, aside from letting you have multiple static events across multiple types. I don’t believe you can do what you’re trying to do as well. You will still need to use a concrete type to access the static Click delegate.

A non-generic, but reusable component that you reference via the inspector would get the same effect without the need for so many different implementations.

I could implement reusable components, but my approach uses csharp events and minimal to none inspector references.

How would the non-generic approach look like? Could I select from inspector the static event I want to use? Or you mean to totally abandon the generic classes approach?

No, nothing static can be serialised.

You can still use C# events, you’d just reference the component you want to hook into the delegates of.

It’d just look like this:

public class ClickButtonHandler : MonoBehaviour, IPointerClickHandler
{
    public event Action Click;

    public void OnPointerClick(PointerEventData eventData)
    {
        ClickButton();
    }

    protected virtual void ClickButton()
    {
        Click.Invoke();
    }
}

Following spiney199’s suggestions I ended up with the following:

I created a button handler script that I attach to every button I want to invoke click events

using System;
using UnityEngine;
using UnityEngine.EventSystems;

public class ClickButtonHandler : MonoBehaviour,IPointerClickHandler
{   
    public event Action Click;

    public void OnPointerClick(PointerEventData eventData)
    {
        InvokeEvent();
    }

    protected virtual void InvokeEvent()
    {
        Click.Invoke();
    }
}

I reference all ClickButtonHandler instances in a singleton EventsManager:

using UnityEngine;
using System;

public class EventsManager : Singleton<EventsManager>
{
    #region Button Handlers

    public ClickButtonHandler buttonOptionsHandler;
    public ClickButtonHandler buttonLoginHandler;
    public ClickButtonHandler buttonSignupHandler;
    public ClickButtonHandler buttonShowSignupScreenHandler;

    #endregion
    protected override void OnEnable()
    {
        if (Instance == null)
        {

        }
        base.OnEnable();
    }  
  
}

Then I created a base class for the toggleable panels:

using UnityEngine;

public abstract class ToggleablePanel : MonoBehaviour
{
    protected ClickButtonHandler clickButtonHandler;
    protected virtual void Start()
    {
       
    }

    protected virtual void Toggle()
    {
        EventsManager.OnTogglePanel(GetComponent<CanvasGroup>());
    }

    protected virtual void OnDisable()
    {
        if (EventsManager.Instance != null)
        {
            clickButtonHandler.Click -= Toggle;
        }
    }

}

And every Toggleable panel inherits the base class and defines the ClickButtonHandler instance that is going to be used:

public class Options : ToggleablePanel  
{   
    protected override void Start()
    {
        clickButtonHandler = EventsManager.Instance.buttonOptionsHandler;
        clickButtonHandler.Click += Toggle;
    }  
}

And finally I opted for composition instead of inheritance for the event listeners:

using UnityEngine;

public class ToggleablePanel : MonoBehaviour
{
    private CanvasGroup canvasGroup;
    private ClickButtonHandler clickButtonHandler;
    public void Initialize(ClickButtonHandler _clickButtonHandler,CanvasGroup _canvasGroup)
    {
        canvasGroup = _canvasGroup;
        clickButtonHandler = _clickButtonHandler;
        clickButtonHandler.Click += Toggle;
    }  

    private void Toggle()
    {
        EventsManager.OnTogglePanel(canvasGroup);
    }

    protected virtual void OnDisable()
    {       
        clickButtonHandler.Click -= Toggle;       
    }

}
using UnityEngine;

public class Options : MonoBehaviour  
{
    private ToggleablePanel toggleablePanel;

    private void Start()
    {
        toggleablePanel = gameObject.AddComponent<ToggleablePanel>();
        toggleablePanel.Initialize(EventsManager.Instance.buttonOptionsHandler, GetComponent<CanvasGroup>());
       
    }
}