使用AddeventHandler动态加载DLL [英] Dynamic Load DLL with AddeventHandler

查看:64
本文介绍了使用AddeventHandler动态加载DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在stackoverflow和msdn上走过很多篇文章,并尝试了它们的解决方案,但是我仍然无法使它正常工作,所以我希望有人能帮助我。非常感谢

I have walkthru much post of stackoverflow and msdn and tried their solution , but I still cannot get it works, so I hope anyone can help me out . Thank you very much

首先我还没有添加

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

直接致电

 ei.AddEventHandler(instance, handler);

然后错误是


类型为'xxxxErrorEventHandler'的对象不能转换为类型
'xxxxErrorEventHandler'。

Object of type 'xxxxErrorEventHandler' cannot be converted to type 'xxxxErrorEventHandler'.

然后我跟随一些帖子如下修改我的代码,然后在CreateDelegate

Then I follow some post modify my code as below, then raise the error when 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楼


reply to floor 1

汉斯,非常感谢您的回答,我按照您的建议修改了我的代码。如果回调函数这样声明

Hi Hans, Thanks a lot for your answer, I following your advise to modify my code. If the Callback function declare like this

private static void Callback(string msg)

并且在ClassA事件中也这样声明

and inside ClassA event also declare like this

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)

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

it comes up error " Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type." when run

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

您知道为什么吗,真的非常感谢您的帮助。

Do you know why , by the way really really thanks for your help.

如果在EXE端修改的代码类似,则报错:

error if the modified code at EXE side like:

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


推荐答案

您的程序有两个委托类型,分别为ErrorEventHandler。一个在上部摘要中声明,另一个在下部摘要中声明。它们具有不同的名称,甚至可能不在同一个命名空间中,但这实际上并不重要。

Your program has two delegate types named ErrorEventHandler. One declared in the upper snippet, another declared in the lower snippet. They have distinct names and probably don't even live in the same namespace, but that doesn't actually matter.

CLR明确拒绝将两种委托类型视为相同,即使它们的声明相同。它不会消耗额外的CPU周期来使用反射本身来检查它们是否匹配,代表应该很快,并且检查兼容性并不便宜。类型转换是编译器的工作。因此,它将仅接受完全匹配,您的反射代码需要创建ClassA.ErrorEventHandler类型的委托。当然,您不知道类型,但是它随时可用。它是EventInfo.EventHandlerType。

The CLR categorically refuses to consider two delegate types identical, even if their declaration is the same. It will not burn the extra CPU cycles to use reflection itself to check if they match, delegates are supposed to be fast and there's nothing cheap about checking compatibility. Type conversion is a compiler's job. So it will only accept an exact match, your reflection code needs to create a delegate of type ClassA.ErrorEventHandler. Of course you can't know the type, it is readily available however. It is EventInfo.EventHandlerType.

代码中的第二个问题是委托目标,即引发事件时运行的方法。现在,您传递ClassA.Run(),这当然是不正确的。您需要传递自己的方法,该方法与委托人兼容。看起来可能像这样:

A second problem in your code is the delegate target, the method that runs when the event is raised. You now pass ClassA.Run(), that is not correct of course. You need to pass your own method, one that's compatible with the delegate. It could look like this:

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

并相应地修改反射代码:

And modify the reflection code accordingly:

        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);

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

Note that the Callback event handler used object as the second argument type. Which is fine, it is compatible with the invisible ErrorEventArgs type. If you need to obtain the values of the passed object then you need to use Reflection in the callback as well.

这篇关于使用AddeventHandler动态加载DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆