2014-04-22 50 views
0

我已經walkthru stackoverflow和msdn的很多帖子和嘗試他們的解決方案,但我仍然無法得到它的作品,所以我希望任何人都可以幫助我。非常感謝您動態加載DLL與AddeventHandler

首先我還沒有加入

MethodInfo mi = instance.GetType().GetMethod(sMethodName, myBindingFlags); 
Delegate del = Delegate.CreateDelegate(typeof(ErrorEventHandler), null, mi); 

直接調用

ei.AddEventHandler(instance, handler); 

那麼錯誤是

對象類型 'xxxxErrorEventHandler' 不能轉換爲類型 'xxxxErrorEventHandler'。

然後我按照一些後修改我的代碼如下,然後引發錯誤時createDelegate方法

DLL:

public class ErrorEventArgs : EventArgs 
{ 
    public string ErrorMsg; 
} 

public interface IClassA 
{ 
    bool Run();   
} 

public class ClassA : IClassA 
{  

    public delegate void ErrorEventHandler(object sender, ErrorEventArgs data); 
    public event ErrorEventHandler OnErrorHandler; 
    public void OnError(object sender, ErrorEventArgs data) 
    { 
     if (OnErrorHandler != null) 
     { 
      OnErrorHandler(this, data); 
     } 
    } 

    public bool Run() 
    { 
     // do something inside DLL 
     ErrorEventArgs data = new ErrorEventArgs(); 
     data.ErrorMsg = "Hello World"; 
     OnError(this, data) 
    } 
} 

EXE:

public delegate void ErrorEventHandler(object sender, ErrorEventArgs data); 

void main() 
{ 
    Assembly assembly = Assembly.LoadFile("myDLL.dll"); 
    Type[] types = assembly.GetTypes(); 
    for (int i = 0; i < types.Length; i++) 
    { 
     Type type = assembly.GetType(types[i].FullName); 
     if (type.GetInterface("myDLL.IClassA") != null) 
     { 
      object obj = Activator.CreateInstance(type); 
      if (obj != null) 
      { 
       MethodInfo methodInfo = obj.GetType().GetMethod("Run"); 

       ErrorEventHandler handler = foo; 
       BindingFlags myBindingFlags = BindingFlags.Instance | BindingFlags.Public; 
       EventInfo ei = instance.GetType().GetEvent("OnErrorHandler", myBindingFlags); 
       MethodInfo mi = instance.GetType().GetMethod("Run", myBindingFlags); 

       *// System.ArgumentException raised here 
       // Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.* 
       Delegate del = Delegate.CreateDelegate(typeof(ErrorEventHandler), null, mi); 
       ei.AddEventHandler(instance, del); 

       bool Result = methodInfo.Invoke(instance, null); 
      } 
     }        
    } 


    public void foo(object sender, ErrorEventArgs data) 
    { 
     Console.WriteLine("In Foo!"); 
    } 
} 

回覆樓層1

嗨漢斯,非常感謝您的回答,我遵循您的建議修改我的代碼。如果回調函數聲明這樣

private static void Callback(string msg) 

和ClassA的事件中也聲明這樣

public delegate void ErrorEventHandler(string msg); 
public event ErrorEventHandler OnErrorHandler; 
public void OnError1(string msg) 
{ 
    if (OnErrorHandler != null) 
    { 
     OnErrorHandler(msg); 
    } 
} 

工作正常,但如果聲明它像以前一樣

private static void Callback(object sender, ErrorEventArgs data) 

它出現錯誤「無法綁定到目標方法,因爲它的簽名或安全透明與代理類型不兼容。」當運行

Delegate del = Delegate.CreateDelegate(ei.EventHandlerType, null, mycallback); 

你知道爲什麼,順便說一句,真的非常感謝你的幫助。

錯誤,如果在EXE側像修改後的代碼:

 ....... 
     BindingFlags myBindingFlags = BindingFlags.Instance | BindingFlags.Public; 
     EventInfo ei = instance.GetType().GetEvent("OnErrorHandler", myBindingFlags); 
     MethodInfo mi = instance.GetType().GetMethod(sMethodName, myBindingFlags); 
     var mycallback = typeof(ModuleManager).GetMethod("Callback", BindingFlags.Static | BindingFlags.NonPublic); 
     Delegate del = Delegate.CreateDelegate(ei.EventHandlerType, null, mycallback); 
     ei.AddEventHandler(instance, del); 
     ....... 



private static void Callback(object sender, ErrorEventArgs data) 
{ 
     Console.WriteLine("In Callback!"); 
} 

回答

2

你的程序有命名ErrorEventHandler委託類型。一個在上面的片段中聲明,另一個在下面的片段中聲明。它們具有不同的名稱,甚至可能不在同一個命名空間中,但這並不重要。

CLR明確拒絕考慮兩個相同的委託類型,即使它們的聲明是相同的。它不會消耗額外的CPU週期來使用反射本身來檢查它們是否匹配,代表應該是快速的,並且檢查兼容性沒有任何便宜。類型轉換是編譯器的工作。所以它只接受一個完全匹配,你的反射代碼需要創建一個類型爲ClassA.ErrorEventHandler的委託。當然,你不知道這種類型,但它是隨時可用的。它是EventInfo.EventHandlerType。

代碼中的第二個問題是委託目標,即引發事件時運行的方法。你現在通過ClassA.Run(),當然這是不正確的。你需要傳遞你自己的方法,一個與代理兼容的方法。它看起來是這樣的:

private static void Callback(object sender, object data) { 
     // etc... 
    } 

並修改相應的反射代碼:

 object obj = Activator.CreateInstance(type); 
     BindingFlags myBindingFlags = BindingFlags.Instance | BindingFlags.Public; 

     // Find the event and its type 
     EventInfo ei = obj.GetType().GetEvent("OnErrorHandler", myBindingFlags); 
     var delegateType = ei.EventHandlerType; 

     // Use our own event handler 
     var mycallback = typeof(Program).GetMethod("Callback", BindingFlags.Static | BindingFlags.NonPublic); 
     Delegate del = Delegate.CreateDelegate(delegateType, null, mycallback); 
     ei.AddEventHandler(obj, del); 

     // Call the Run method 
     MethodInfo methodInfo = obj.GetType().GetMethod("Run"); 
     bool Result = (bool)methodInfo.Invoke(obj, null); 

注意回調事件處理程序使用對象作爲第二個參數的類型。這很好,它與不可見的ErrorEventArgs類型兼容。如果您需要獲取傳遞對象的值,則還需要在回調中使用Reflection。

+0

嗨漢斯,謝謝你的幫助。我已經測試過,部分代碼正在工作,但仍然存在一些問題。我描述了問題線程中的細節。你能幫忙看看。謝謝 – user3440306

+0

在我看來,你通過在Callback()方法中使用ErrorEventArgs再次犯了同樣的錯誤。你沒有正確的類型,所以你必須使用* object *來代替。如答案中所述,您必須在方法中使用反射來獲取* data *成員值。 –

+0

感謝您的幫助和答覆。我得到了你的答案。非常感謝 – user3440306