我在使用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)
答案 0 :(得分:3)
Action<object>
是一种可以接受任何作为参数的方法。 Action<T>
是一个对象,只能接受类型为T
的对象作为参数。如果您可以将Action<T>
视为Action<object>
,则可以传递不属于T
类型的对象,但该操作无法接受对象不属于T
的类型,因此编译器禁止您这样做。
答案 1 :(得分:0)
您尝试做的是将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);
}
注意:如果可以将对象强制转换为接受的参数类型,这只会触发侦听器,但这样做效率相当低(因为您要为每个侦听器倾听那种类型)
答案 2 :(得分:0)
你不能这样做,因为它不安全。它可以让你做
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); });
}