这是我的情况。我需要订阅一个在编译时我不知道的类型的事件。所以,我试图动态订阅这种类型。这不像创建EventHandler类型的委托那么简单,因为它并不总是正确的类型。
所以,这是我第一次进入Reflection.Emit命名空间,我需要一些帮助。这就是我到目前为止所做的:
private Delegate CreateDynamicClosedDelegate(Type eventHandlerType)
{
var handler = new DynamicMethod(string.Empty, null, GetDelegateParameterTypes(eventHandlerType));
ILGenerator ilgen = handler.GetILGenerator();
var onTargetWindowClosedMethodInfo = GetType().GetMethod("OnTargetWindowClosed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
// this.OnTargetWindowClosed
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, onTargetWindowClosedMethodInfo);
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ret);
return handler.CreateDelegate(eventHandlerType);
}
如您所见,我正在为特定事件类型(在运行时确定)创建委托。我想我几乎就在那里,我只需要得到#34;这个。"一部分。
如果我理解正确的话,ilgen.Emit(OpCodes.Ldarg_0);应该在堆栈上加载实例。但是,由于它是一个静态事件处理程序,我认为第一个参数是sender,它不是包含该方法的实例。
最后,我正在尝试制作此代码:
window.Closed += (sender, e) => this.OnTargetWindowClosed();
订阅活动超出范围(这很容易),但我该如何创建此方法:
this.OnTargetWindowClosed();
答案 0 :(得分:2)
如果要使用DynamicMethod在堆栈上指定实例,则必须使用其他构造函数重载。所有者类型是您实例的类型。
public DynamicMethod(string name, Type returnType, Type[] parameterTypes, Type owner);
创建委托时,必须使用此重载,目标参数是您的实例。
public Delegate CreateDelegate(Type delegateType, object target);
在您的情况下,它看起来像这样:
private Delegate CreateDynamicClosedDelegate(Type eventHandlerType)
{
var handler = new DynamicMethod(string.Empty, null, GetDelegateParameterTypes(eventHandlerType), this.GetType());
ILGenerator ilgen = handler.GetILGenerator();
var onTargetWindowClosedMethodInfo = GetType().GetMethod("OnTargetWindowClosed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
// this.OnTargetWindowClosed
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, onTargetWindowClosedMethodInfo);
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ret);
return handler.CreateDelegate(eventHandlerType, this);
}
如果你正在使用silverlight,你可以这样做:
public class Dict : Dictionary<int, WindowLogic>
{
public WindowLogic Get(int key)
{
return this[key];
}
}
public class WindowLogic : IDisposable
{
static public readonly Dict Instances = new Dict();
static private int s_increment = 0;
private int _increment;
public WindowLogic()
{
lock (Instances)
{
Instances.Add(_increment = ++s_increment, this);
}
}
private Delegate CreateDynamicClosedDelegate(Type eventHandlerType)
{
var handler = new DynamicMethod(string.Empty, null, GetDelegateParameterTypes(eventHandlerType));
ILGenerator ilgen = handler.GetILGenerator();
var onTargetWindowClosedMethodInfo = GetType().GetMethod("OnTargetWindowClosed", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
// this.OnTargetWindowClosed
ilgen.Emit(OpCodes.Ldsfld, typeof(WindowLogic).GetField("Instances", BindingFlags.Static | BindingFlags.Public));
ilgen.Emit(OpCodes.Ldc_I4, _increment);
ilgen.Emit(OpCodes.Call, typeof(Dict).GetMethod("Get"));
ilgen.Emit(OpCodes.Call, onTargetWindowClosedMethodInfo);
ilgen.Emit(OpCodes.Ret);
return handler.CreateDelegate(eventHandlerType);
}
public void OnTargetWindowClosed()
{
throw new NotImplementedException();
}
private Type[] GetDelegateParameterTypes(Type eventHandlerType)
{
throw new NotImplementedException();
}
public void Dispose()
{
Instances.Remove(_increment);
}
}