我需要能够从课堂外引发事件,所以我认为反射是解决方案。但是,在检索到事件MultiCastDelegate
及其调用方法后,我无法调用它。当我这样做时,我收到一条TargetException
消息“对象与目标类型不匹配”。
这是一些重现问题的代码:
一个助手类:
public static class Reflection
{
public static MethodInfo GetEventMethod(this object obj, string eventName, out Type targetType)
{
if (obj == null) throw new ArgumentNullException("obj");
if (string.IsNullOrEmpty(eventName)) throw new ArgumentNullException("eventName");
var mcDelegate = getEventMulticastDelegate(obj, eventName, out targetType);
return mcDelegate != null ? mcDelegate.Method : null;
}
private static MulticastDelegate getEventMulticastDelegate(object obj, string eventName, out Type targetType)
{
// traverse inheritance tree looking for the specified event ...
targetType = obj.GetType();
while (true)
{
var fieldInfo = targetType.GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.GetField);
if (fieldInfo != null)
return fieldInfo.GetValue(obj) as MulticastDelegate;
if (targetType.BaseType == null)
return null;
targetType = targetType.BaseType;
}
}
public static void RaiseEvent(this object obj, string eventName, params object[] parameters)
{
Type targetType;
var methodInfo = obj.GetEventMethod(eventName, out targetType);
if (methodInfo == null)
throw new ArgumentOutOfRangeException("eventName", string.Format("Cannot raise event \"{0}\". Event is not supported by {1}", eventName, obj.GetType()));
var targetObj = obj;
if (targetType != obj.GetType())
targetObj = obj.ConvertTo(targetType);
methodInfo.Invoke(targetObj, parameters); // *** ERROR HERE ***
}
}
和一些代码来测试它:
[TestClass]
public class Reflection
{
[TestMethod]
public void RaiseReflectedEvent()
{
var bar = new Bar();
var isRaised = false;
bar.TestEvent += (sender, args) => isRaised = true;
bar.RaiseEvent("TestEvent", this, new EventArgs());
Assert.IsTrue(isRaised);
var foo = new Foo();
isRaised = false;
foo.TestEvent += (sender, args) => isRaised = true;
foo.RaiseEvent("TestEvent", this, new EventArgs());
Assert.IsTrue(isRaised);
}
private class Bar
{
public event EventHandler TestEvent;
}
private class Foo : Bar
{
}
}
我一定错过了一些东西,但我目前没有线索,希望能得到任何提示。