使用AddeventHandler动态加载DLL

时间:2014-04-22 10:41:07

标签: c# dll delegates

我有很多关于stackoverflow和msdn的帖子,并尝试了他们的解决方案,但我仍然无法让它工作,所以我希望任何人都可以帮助我。非常感谢你

首先我没有添加

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)

出现错误&#34;无法绑定到目标方法,因为其签名或安全透明度与委托类型的方法不兼容。&#34;运行时

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!");
 }

1 个答案:

答案 0 :(得分: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);

请注意,Callback事件处理程序使用 object 作为第二个参数类型。哪个好,它与不可见的ErrorEventArgs类型兼容。如果需要获取传递对象的值,则还需要在回调中使用Reflection。