带有AddeventHandler的动态加载DLL
本文关键字:加载 DLL 动态 AddeventHandler 带有 | 更新日期: 2023-09-27 17:59:16
我浏览了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)
当运行时,它会出现错误"无法绑定到目标方法,因为它的签名或安全透明性与委托类型不兼容。"
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!");
}
您的程序有两个委托类型,名为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类型兼容。如果需要获得传递对象的值,那么也需要在回调中使用反射。