是否可以删除您的类没有添加的VB.NET EventHandler?

时间:2015-02-03 00:17:06

标签: c# .net vb.net

在我的VB.NET应用程序中,事件AppDomain.CurrentDomain.AssemblyResolve有一个订阅它的处理程序。订阅此事件的ResolveEventHandler已添加到我的代码的上游(据我所知,System.AppDomain有自己的Private Method订阅了该事件... ...是否可以删除这个事件的所有处理程序,以便我可以添加自己的处理程序并确保它是只有一个

基本上我正在尝试这样做:

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf ClassX.MethodX

但是我不知道这个例子中有ClassXMethodX是什么,因为我还没有为这个事件添加处理程序,而且这个处理程序是由上游代码添加的。我正在使用此处描述的方法来检查是否有任何处理程序是订阅事件: https://stackoverflow.com/a/2953318/734914

编辑:我能够在调试时使用立即窗口找出订阅该事件的方法。

?  DirectCast(gettype(System.AppDomain).GetField("AssemblyResolve", BindingFlags.Instance or BindingFlags.NonPublic).GetValue(AppDomain.CurrentDomain) , ResolveEventHandler)
{System.ResolveEventHandler}
    _methodBase: Nothing
    _methodPtr: 157334028
    _methodPtrAux: 1827519884
    _target: {System.ResolveEventHandler}
    **Method: {System.Reflection.Assembly ResolveAssembly**(System.Object, System.ResolveEventArgs)}
    Target: Nothing

现在我正在尝试删除它,就像这样,因为它不是Public方法:

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf GetType(Reflection.Assembly).GetMethod("ResolveAssembly")

但是这给出了一个编译错误:“AddressOf参数必须是方法的名称”。所以我不确定如何在这里指定非公共方法

1 个答案:

答案 0 :(得分:1)

来自原始评论:

Here's一个关于从没有委托签名的事件中移除委托的主题......非常方便,但最后海报说明了

  

“看起来AppDomain.CurrentDomain.AssemblyResolve根本不支持删除事件,所以我发布的代码不起作用。”

甚至.NET抱怨事件System.AppDomain.AssemblyResolve只能显示在+=-=的左侧(+=/-=运算符是C#AddHandler/RemoveHandler )..所以它看起来像'不':/

此外,在您进行编辑后,您无法执行以下操作:

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf GetType(Reflection.Assembly).GetMethod("ResolveAssembly")

因为AddressOf关键字是一个运营商关键字,类似于作为运营商的+-AddressOf对所提供的程序进行操作,且必须是它可以在编译时推断出的过程名称。并且GetMethod函数返回MethodInfo类型而不是已知的函数地址。

然而,一切都没有丢失!

AddHandlerRemoveHandler函数实际上要求传递ObjectDelegateAddressOf汇编成Delegate使用时),所以你不需要AddressOf做你想做的事,你需要一个Delegate

为此,我们可以使用{i>做取MethodInfo个对象的CreateDelegate方法。应该注意的是,由于您尝试访问私有方法,因此您需要指定Reflection.BindingFlags.InstanceReflection.BindFlags.NonPublic的{​​{3}}(我说and但是你'我会对它们进行按位Or,例如:

GetType(Reflection.Assembly).GetMethod("ResolveAssembly", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)

所以在此调用CreateDelegate将为我们提供以下代码

[Delegate].CreateDelegate(GetType(Reflection.Assembly), GetType(Reflection.Assembly).GetMethod("ResolveAssembly", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic))

但这相当冗长,所以让我们分解一下:

Dim type As Type = GetType(Reflection.Assembly)
Dim mi As Reflection.MethodInfo = type.GetMethod("ResolveAssembly", (Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic))

现在,我们只需通过以下内容致电RemoveHandler上的AppDomain.CurrentDomain.AssemblyResolve

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, [Delegate].CreateDelegate(type, mi)

AppDomain.CurrentDomain.AssemblyResolve期望委托/事件签名匹配,因此我们需要将创建的委托转换为适当的类型:

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, CType([Delegate].CreateDelegate(type, mi), System.ResolveEventHandler)

现在,您可以通过事件处理程序的反射删除私有方法。

警告!! 虽然这段代码将编译并运行,但我不保证它的有效性或准确性,因为你正在使用帧和堆栈指针(本质上),所以当它可能运行时它可能工作,它也可能产生小猫..所以要小心。

希望能有所帮助!