【问题标题】:Is it possible to Remove a VB.NET EventHandler that your class didn't Add?是否可以删除您的班级未添加的 VB.NET EventHandler?
【发布时间】:2015-07-18 19:59:43
【问题描述】:

在我的 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

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

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

但这会导致编译器错误:“AddressOf 参数必须是方法的名称”。所以我不确定如何在这里指定非公共方法

【问题讨论】:

  • 不,这是不可能的。
  • 这是 winforms 应用还是类库?
  • 我的代码在一个由 WinForms 应用程序加载的 ClassLibrary 中
  • 这是一个关于从没有代表签名的事件中删除代表的主题:bytes.com/topic/c-sharp/answers/… .. 非常方便,但最后发帖人说 "It looks like AppDomain.CurrentDomain.AssemblyResolve doesn't support removal of events at all so the code I posted won't work." .. 甚至 .NET抱怨 The event 'System.AppDomain.AssemblyResolve' can only appear on the left hand side of += or -= (+=/-= 是 C# AddHandler/RemoveHandler) .. 所以它看起来像一个“不”:/
  • txttechhelp - 您链接中的这段代码正是我所需要的。请将您的回复作为答案发布,以便我将其标记为已接受。 GetInvocationList() 和 info.GetRemoveMethod().Invoke( ... )

标签: c# .net vb.net


【解决方案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),所以你不需要 @ 987654348@ 做你想做的事,你需要一个Delegate

为此,我们可以使用CreateDelegate 方法,该方法确实 采用MethodInfo 对象。应该注意的是,由于您尝试访问私有方法,因此您需要指定Reflection.BindingFlags.InstanceReflection.BindFlags.NonPublicBindFlags(我说and,但您将按位执行Or on他们),例如:

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)

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

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

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

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

希望能帮到你!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-11
    • 1970-01-01
    • 2022-11-29
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2010-10-30
    相关资源
    最近更新 更多