我正在创建一个API,我的目标是公开一个可以像这样调用的方法:
Library.AddCallback<string>(Type.ChatMessage, GotMessage);
private void GotMessage(string message) {
//...
}
//or
Library.AddCallback<int>(Type.Number, GotNumber);
private void GotNumber(int number) {
//...
}
<int>
,<string>
类型可以是任何类型。
在库中,方法如下所示:
public void AddCallback<T1>(object type, Action<T1> callback) {
//...
}
问题是我想以某种方式首先在方法调用之外(在列表中)保存回调,然后才能调用它。
我理想的做法是首先将其投射到一个对象,以便能够将其存储在List<object>
中,然后再将其强制转换为Action<T1>
。然而,似乎不可能将T1保存到变量中(除非通过执行typeof(T1)
拒绝我使用它来将其转换回来)。
我想如何调用它的示例(我从列表中获得type
和data
的位置):
((Action<type>)callback)(data)
答案 0 :(得分:5)
我不确定如何输入data
。假设它现在是object
类型,您可以将Action<T>
分解为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);
}
编辑:你已经将它标记为答案,但这是另一个将回调存储在类型集中的实现。
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);
}
然后您的更高级别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.ChatMessage
或Type.Number
),则不应该太难。
答案 1 :(得分: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
}