调用具有未知类型参数的Action(Action <any>)

Hen*_*son 4 c#

我正在创建一个API,我的目标是公开一个可以像这样调用的方法:

Library.AddCallback<string>(Type.ChatMessage, GotMessage);

private void GotMessage(string message) {
    //...
}
//or
Library.AddCallback<int>(Type.Number, GotNumber);

private void GotNumber(int number) {
    //...
}
Run Code Online (Sandbox Code Playgroud)

类型<int>,<string>可以是任何类型.

在库中,该方法看起来像这样:

public void AddCallback<T1>(object type, Action<T1> callback) {
    //...
}
Run Code Online (Sandbox Code Playgroud)

问题是我想以某种方式首先在方法调用之外(在列表中)保存回调,然后才能调用它.

我理想的做法是首先将它转换为一个对象,以便能够将其存储在a中List<object>,然后再将其强制转换为Action<T1>.然而,似乎不可能将T1保存到变量中(除非通过typeof(T1)拒绝我使用它来将其转换回来).

我想怎么称呼它(在那里我得到实例typedata从列表中):

((Action<type>)callback)(data)
Run Code Online (Sandbox Code Playgroud)

Chr*_*air 5

我不确定怎么data打字.假设它object现在是类型,你可以分解Action<T>to Action<object>并在其中执行强制转换:

private List<Action<object>> Callbacks = new List<Action<object>>();

public void AddCallback<T1>(object type, Action<T1> callback) 
{
    Callbacks.Add((data) => callback((T1)data));
}

public void FireCallback(object data)
{
    Action<object> callback = GetCallback();
    callback(data);
}
Run Code Online (Sandbox Code Playgroud)

编辑:您已经将它标记为答案,但这是另一个将回调存储在类型集中的实现.

A CallbackHandler存储键入的回调列表:

public class CallbackHandler<T> : ICallbackHandler
{
    private List<Action<T>> Callbacks = new List<Action<T>>();

    public void AddCallback<T>(Action<T> callback)
    {
        Callbacks.Add(callback);
    }

    public void Callback(object data)
    {
        T typedData = (T)data;
        foreach(var callback in Callbacks)
            callback(typedData);
    }
}

public interface ICallbackHandler
{
    void Callback(object data);
}
Run Code Online (Sandbox Code Playgroud)

然后你的更高级别Library有这样的事情:

private Dictionary<Type, ICallbackHandler> AllCallbacks = new Dictionary<Type, ICallbackHandler>();

public void AddCallback<T>(Action<T> callback) 
{
    Type type = typeof(T);
    ICallbackHandler handler;
    if (!AllCallbacks.TryGetValue(type, out handler))
    {
        handler = new CallbackHandler<T>();
        AllCallbacks[type] = handler;
    }
    CallbackHandler<T> typedHandler = (CallbackHandler<T>)handler;
    typedHandler.AddCallback(callback);
}

public void FireCallback(object data)
{
    Type type = data.GetType();
    ICallbackHandler handler;
    AllCallbacks.TryGetValue(type, out handler);
    if (handler != null)
        handler.Callback(data);
}
Run Code Online (Sandbox Code Playgroud)

这假设data确定要触发哪个回调的类型.如果你需要再添加一个级别(基于Type.ChatMessageType.Number),它应该不会太难.