クラスの外からイベントを発生させる必要があるので、リフレクションが解決策だと思いました。ただし、イベント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
{
}
}
私は何かを見逃したに違いありませんが、現在手がかりがなく、ヒントをいただければ幸いです。