我在C#中实现EventHandler时遇到了一些问题。我似乎无法将Action<T>
强制转换为Action<object>
以存储在列表中。
private readonly IList<Action<object>> listeners;
public EventHandler() {
listeners = new List<Action<object>>();
}
public void RegisterListener<T>(Action<T> listener) where T : class {
Listeners.Add((Action<object>)listener);
}
private void ReciveEvent(object evt) {
if (evt != null)
Listeners.Where(l => l.GetGeneric(0).
IsAssignableFrom(evt.GetType())).
AsParallel().ForAll(l => l(evt));
}
我刚刚得到一个铸造异常:
Unable to cast object of type 'System.Action`1[Events.SendTestEvent]' to type 'System.Action`1[System.Object]'.
Events.SendTestEvent <- My current test object... it is just a class with a single property and no parent(besides obj)
Action<object>
是一个可以接受任何作为其参数的方法。Action<T>
是一个只能接受类型为T
的对象作为其参数的对象。如果您可以将Action<T>
视为Action<object>
,那么您可以传递一个不是T
类型的对象,但该操作不能接受不是T
的对象,因此编译器禁止您这样做。
您要做的是将Action<T>
强制转换为Action<object>
,这是不可能的。您可以创建一个新的Action来触发方法传递的操作,并将其插入到您的列表中,如下所示:
public void RegisterListener<T>(Action<T> listener) where T : class
{
Action<object> wrappingAction = (arg)=>
{
var castArg = arg as T;
if(castArg != null)
{
listener(castArg);
}
};
Listeners.Add(wrappingAction);
}
注意:只有当对象可以转换为可接受的参数类型时,这才会触发侦听器,但是,这是相当低效的(因为您将为每个侦听该类型的侦听器进行转换)
你不能这样做,因为这不安全。它可以让你做
RegisterListener<string>(s => { Console.WriteLine(s); });
Action<object> a = listeners[0];
a(3);
您可以将给定的处理程序封装在调用时转换为目标类型的处理程序中,例如
public void RegisterListener<T>(Action<T> listener) where T : class {
Listeners.Add(o => { listener((T)o); });
}