是否可以删除您的 class 未添加的 VB.NET EventHandler?

Is it possible to Remove a VB.NET EventHandler that your class didn't Add?

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

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

RemoveHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf ClassX.MethodX

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

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

?  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 parameter must be the name of a method"。所以我不确定如何在此处指定非Public方法

来自原评论:

Here's 一个关于从您没有代表签名的事件中删除代表的主题......非常方便,但最后发帖人说

"It looks like AppDomain.CurrentDomain.AssemblyResolve doesn't support removal of events at all so the code I posted won't work."

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

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

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

是因为AddressOf keyword is an operator keyword, similar to a + or - being an operator, the AddressOf operates on the procedure given and it must be a procedure name it can deduce at compile time. And the GetMethod function returns a MethodInfo类型而不是已知的函数地址。

然而万事俱备!

AddHandler and RemoveHandler functions actually call for an Object and Delegate to be passed in (AddressOf gets compiled into a Delegate when used), so you don't need the AddressOf to do what you want, you need a Delegate.

要做到这一点,我们可以使用 Reflection.BindingFlags.InstanceReflection.BindFlags.NonPublicCreateDelegate method which does take a MethodInfo object. It should be noted that since you're trying to access private methods, you'll need to specify the BindFlags(我说 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))

现在我们可以通过以下方式简单地调用 AppDomain.CurrentDomain.AssemblyResolve 上的 RemoveHandler

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

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

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

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

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

希望能帮到你!