Home > front end >  How to use params of object in Action
How to use params of object in Action

Time:09-17

While creating a UI system, I am trying to create a UI event handler that takes a variable length parameter and performs an action.

Here is my code

class UIEventTriggerManager : MonoBehaviour
{
    public static UIEventTriggerManager Instance;

    private void Awake()
    {
        Instance = this;
    }

    public void Publish(string key, params object[] args)
    {
        m_eventHandler[key]?.Invoke(args);
    }

    public void Subscribe(string eventName, Action<object[]> action)
    {
        if (m_eventHandler.ContainsKey(eventName) == false)
        {
            m_eventHandler.Add(eventName, action);
        }
        else
        {
            m_eventHandler[eventName]  = action;
        }
    }
}
class CharacterUI
{
    public void FirstOpen()
    {
        UIEventTriggerManager.Instance.Subscribe("ChagedCharacter", ChagedCharacter); // ChagedCharacter error

        UIEventTriggerManager.Instance.Subscribe("ChagedCharacter2", ChagedCharacter2); // error

        UIEventTriggerManager.Instance.Subscribe("ChagedCharacter3", ChagedCharacter3); // error
    }

    public void ChagedCharacter()
    {
         //....
    }

    public void ChagedCharacter2(int a)
    {
         //....
    }

    public void ChagedCharacter3(int a, string b, float c)
    {
         //....
    }

}

How to use Subscribe 'ChangedCharacter' Method??

Do I have to add 'params object[] args' to the method argument??

I know syntax error but I need an event handler to manage multiple parameters.

I'm trying to implement it this way, please give me some advice.

CodePudding user response:

The params does only exist in the signature of

Publish(string key, params object[] args)

meaning you can call this method with additional parameters - or not. Inside this method it is simply an object[] of variable length. If no args was passed in at all it will simply be an empty array.

Also yourself already seem to know that Action<object[]> simply takes an object[] - no params here.

Action<object[]> basically is nothing else than a shorthand for

public delegate void SomeName(object[] args);

Therefore also the listener method is simply

// Should it be "Changed" btw?
public void ChagedCharacter(object[] args)

and it is the responsibility of this (and any listener) to correctly handle the array.

The error should actually tell you exactly which signature ChagedCharacter was expected to have.

You could then e.g. do

private void ChagedCharacter(object[] args)
{
    switch(args.Length)
    {
        case 0:
            ChagedCharacter ();
            break;

        case 1 when args[0] is int intValue :
            ChagedCharacter (intValue);
            break;

        case 3 when args[0] is int intValue && args[1] is string stringValue && args[2] is float floatValue:
            ChagedCharacter (intValue, stringValue, floatValue);
            break;

        default:
            break;
            
    }
}

But honestly before you do that you rather overthink your design ...

CodePudding user response:

Maybe this solution is enough for you. and this solution also have boxing unboxing , So maybe can use <T> to replace object[] to avoid.

public enum EventType
{
    ChagedCharacter,
    ChagedCharacter2
}

public class UIEventTriggerManager : MonoBehaviour
{
    public static UIEventTriggerManager Instance;

    private void Awake()
    {
        Instance = this;
    }
    static Dictionary<EventType, List<IReciveEvent>> recives = new Dictionary<EventType, List<IReciveEvent>>();

    public void Publish(EventType key, params object[] args)
    {
        if (recives.ContainsKey(key))
        {
            foreach(IReciveEvent ir in recives[key])
            {
                ir.GetEvent(key,args);
            }
        }
    }

    public void Subscribe(EventType type , IReciveEvent ui)
    {
        if(!recives.ContainsKey(type))
        {
            recives[type] = new List<IReciveEvent>();
        }

        if(!recives[type].Contains(ui))
        {
            recives[type].Add(ui);
        }
    }
}

public interface IReciveEvent
{
    void GetEvent(EventType type, object[] objs);
}

public class CharUI : MonoBehaviour, IReciveEvent
{
    private void Awake()
    {
        UIEventTriggerManager.Instance.Subscribe(EventType.ChagedCharacter, this);
        UIEventTriggerManager.Instance.Subscribe(EventType.ChagedCharacter2, this);
    }

    public void GetEvent(EventType type, object[] objs)
    {
        if(type == EventType.ChagedCharacter)
        {
            //todo
        }
        else if ( type == EventType.ChagedCharacter2)
        {
            int a = (int)objs[0];
            //todo
        }
        //....
    }
}
  • Related