5

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

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

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

private void GotNumber(int number) {
    //...
}

type <int><string>可以是任何类型。

在库中,该方法如下所示:

public void AddCallback<T1>(object type, Action<T1> callback) {
    //...
}

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

我理想情况下想要做的是首先将其转换为能够将其存储在 a 中的对象List<object>,然后将其转换回Action<T1>. 但是,似乎不可能将 T1 保存到变量中(除非这样做typeof(T1)拒绝我使用它来将其转换回来)。

我想如何调用它的示例(我从列表中获得type的位置data):

((Action<type>)callback)(data)
4

2 回答 2

5

我不确定如何data输入。假设它object现在是类型,您可以分解Action<T>toAction<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);
}

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

ACallbackHandler存储类型化的回调列表:

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);
}

然后你的更高级别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);
}

这是假设 的类型data确定要触发的回调。如果您需要在其上增加一个级别(基于Type.ChatMessageor Type.Number),这应该不会太难。

于 2013-05-31T10:24:10.037 回答
1

你可以这样做:

List<object> callbacks = new List<object>();

public void AddCallback<T1>(object type, Action<T1> callback)
{
    this.callbacks.Add(callback);
}

public IEnumerable<Action<T>> GetCallbacks<T>()
{
    return this.callbacks.OfType<Action<T>>();
}

并像这样使用它:

// Sample callbacks
static void Foo(int i) { Console.WriteLine("Foo {0}", i); }
static void Bar(string s) { Console.WriteLine("Bar {0}", s); }

AddCallback(null, (Action<int>)(Foo));
AddCallback(null, (Action<string>)(Bar));

foreach (var callback in GetCallbacks<int>())
{
    callback(42); // only calls Foo
}
于 2013-05-31T10:37:07.720 回答