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
}
//....
}
}