我试图在事件发生时触发一个操作,忽略事件参数(至少目前是这样)。我通过反射找到事件,然后创建一个与预期签名匹配的动态方法(不能保证只有Sender/EventArgs),然后尝试调用该操作。
bool TryAsEvent(Type type, UIElement element, string actionStr, Action act)
{
try
{
var eventInfo = type.GetEvent(actionStr);
var eventType = eventInfo.EventHandlerType;
var methodInfo = eventType.GetMethod("Invoke");
var parameterInfos = methodInfo.GetParameters();
var paramTypes = parameterInfos.Select((info => info.ParameterType)).ToArray();
var dynamicMethod = new DynamicMethod("", typeof(void), paramTypes);
MethodInfo exec = typeof(ThisClass).GetMethod("ExecuteEvent");
var il = dynamicMethod.GetILGenerator();
il.DeclareLocal(typeof(MethodInfo));
il.Emit(OpCodes.Ldobj, act.Method);
il.EmitCall(OpCodes.Call, exec, null);
il.Emit(OpCodes.Ret);
var handler = dynamicMethod.CreateDelegate(eventType);
eventInfo.AddEventHandler(element, handler);
return true;
}
catch
{
return false;
}
}
public static void ExecuteEvent(MethodInfo i)
{
i.Invoke(null, null);
}
有人能告诉我如何做到这一点吗?
更新:这是一个模仿真实场景的简洁的VS11项目文件:
Download
更新(修复):
public class Program
{
public static void Main(string[] args)
{
var x = new Provider();
new Program().TryAsEvent(
x.GetType(),
x,
"Click",
new Program().TestInstanceMethod);
x.Fire();
Console.ReadLine();
}
public void TestInstanceMethod()
{
Console.WriteLine("Action fired when event did.");
}
bool TryAsEvent(Type type, object element, string actionStr, Action act)
{
try
{
var getMFromH = typeof(MethodBase)
.GetMethod("GetMethodFromHandle",
BindingFlags.Public | BindingFlags.Static,
null,
new[] { typeof(RuntimeMethodHandle) }, null);
var eventInfo = type.GetEvent(actionStr);
var eventType = eventInfo.EventHandlerType;
var methodInfo = eventType.GetMethod("Invoke");
var parameterInfos = methodInfo.GetParameters();
var paramTypes = parameterInfos.Select((info => info.ParameterType)).ToArray();
var target = act.Target;
if (target != null)
paramTypes = new[] {target.GetType()}.Union(paramTypes).ToArray();
var dynamicMethod = new DynamicMethod("", typeof(void), paramTypes);
var exec = typeof (Program).GetMethod
(target != null
? "ExecuteEvent"
: "ExecuteEventStati");
var il = dynamicMethod.GetILGenerator();
if (target != null)
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldtoken, act.Method);
il.Emit(OpCodes.Call, getMFromH);
il.Emit(OpCodes.Call, exec);
il.Emit(OpCodes.Ret);
var handler =
target != null
? dynamicMethod.CreateDelegate(eventType, target)
: dynamicMethod.CreateDelegate(eventType);
eventInfo.AddEventHandler(element, handler);
return true;
}
catch (Exception ex)
{
Console.WriteLine("Exception: " + ex);
return false;
}
}
public static void ExecuteEventStati(MethodInfo i)
{
i.Invoke(null, null);
}
public static void ExecuteEvent(object o, MethodInfo i)
{
i.Invoke(o, null);
}
}
下面是该示例的无关代码(以防有人想要复制和粘贴):
public class Provider
{
public event MyRoutedEventHandler Click;
public void Fire()
{
if (Click != null)
Click(this, new MyRoutedEventArgs());
}
}
public delegate void MyRoutedEventHandler(object sender, MyRoutedEventArgs e);
public class MyRoutedEventArgs : RoutedEventArgs
{
public MyRoutedEventArgs()
{
}
public MyRoutedEventArgs(RoutedEvent routedEvent)
: this(routedEvent, (object)null)
{
}
public MyRoutedEventArgs(RoutedEvent routedEvent, object source)
: base(routedEvent, source){}
}