2011-11-14 19 views
0

這是我的情況。我需要在編譯時訂閱一個我不知道的類型的事件。所以,我試圖動態訂閱這種類型。這不像創建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); 
} 

正如你所看到的,我創建了一個特定的事件類型的委託(這是在運行時確定)。我想我幾乎在那裏,我只需要得到「這個」。部分。

如果我理解正確,ilgen.Emit(OpCodes.Ldarg_0);應該在堆棧上加載實例。但是,由於它是一個靜態事件處理程序,我認爲第一個參數是發件人,而不是包含該方法的實例。

最後,我想產生這樣的代碼:

window.Closed += (sender, e) => this.OnTargetWindowClosed(); 

訂閱該事件超出範圍(即容易),但我怎麼能創造這個方法:

this.OnTargetWindowClosed(); 

回答

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); 
    } 
} 
+0

感謝您的快速回復。問題是我使用silverlight,當我使用這個: var handler = new DynamicMethod(string.Empty,null,GetDelegateParameterTypes(eventHandlerType),this.GetType()); 嘗試通過安全透明方法'MVVMProviders.Logic.WindowLogic.CreateDynamicClosedDelegate(System.Type)'來訪問安全關鍵方法'System.Reflection.Emit.DynamicMethod..ctor(System.String,System.Type,System.Type [ ],System.Type)'失敗。 –

+0

謝謝,作品像魅力! –

相關問題