You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET中如何在类内判断另一类是否绑定了对应事件的处理程序

结论

你期望的DoSomething.WasHandled这种直接判断语法在VB.NET中没有原生提供,但可以通过自定义事件管理委托列表或反射的方式实现需求,无需为事件添加额外参数。

推荐实现方案(自定义事件)

通过VB.NET的Custom Event语法手动管理事件的订阅委托列表,直接获取订阅者信息判断是否存在类B的处理程序:

Public Class A
    ' 存储事件所有订阅者的委托字段
    Private DoSomethingHandler As Action

    ' 自定义事件的订阅、退订、触发逻辑
    Public Custom Event DoSomething As Action
        AddHandler(value As Action)
            DoSomethingHandler = [Delegate].Combine(DoSomethingHandler, value)
        End AddHandler
        RemoveHandler(value As Action)
            DoSomethingHandler = [Delegate].Remove(DoSomethingHandler, value)
        End RemoveHandler
        RaiseEvent()
            DoSomethingHandler?.Invoke()
        End RaiseEvent
    End Event

    Public Sub RaiseDoSomething()
        RaiseEvent DoSomething()
        ' 判断是否存在类B实例订阅的处理程序
        Dim hasBHandler = DoSomethingHandler?
                            .GetInvocationList()?
                            .Any(Function(d) d.Target?.GetType() = GetType(B))
        If hasBHandler = True Then
            DoSomethingElse()
        End If
    End Sub

    Private Sub DoSomethingElse()
        ' 存在类B处理程序时执行的逻辑
    End Sub
End Class

Public Class B
    Public WithEvents SomeA As New A

    Private Sub HandleDoSomething() Handles SomeA.DoSomething
        ' 事件处理逻辑
    End Sub
End Class

方案说明

  • Custom Event语法允许你完全掌控事件的委托列表存储,不需要依赖编译器隐式生成的内部字段
  • 调用委托的GetInvocationList()方法可以拿到所有订阅该事件的委托实例,每个委托的Target属性就是处理程序所属的类实例
  • 只需要判断Target的类型是否为B,就能确认类B是否存在对应事件的处理程序,完全不需要修改事件参数

替代实现方案(反射)

如果你不想修改原有事件的定义,可以通过反射读取编译器为隐式事件生成的后台委托字段实现相同判断:

Public Class A
    Public Event DoSomething()

    Public Sub RaiseDoSomething()
        RaiseEvent DoSomething()
        ' 反射读取VB编译器为DoSomething事件隐式生成的委托字段
        Dim eventField = GetType(A).GetField("DoSomethingEvent", 
                            System.Reflection.BindingFlags.Instance Or 
                            System.Reflection.BindingFlags.NonPublic)
        Dim handler = CType(eventField.GetValue(Me), Action)
        Dim hasBHandler = handler?
                            .GetInvocationList()?
                            .Any(Function(d) d.Target?.GetType() = GetType(B))
        If hasBHandler = True Then
            DoSomethingElse()
        End If
    End Sub

    Private Sub DoSomethingElse()
        ' 存在类B处理程序时执行的逻辑
    End Sub
End Class

方案说明

  • VB编译器默认会为隐式声明的事件生成命名规则为[事件名]Event的私有委托字段,反射读取该字段即可拿到所有订阅者
  • 该方案不需要修改原有事件定义,但依赖编译器的内部命名规则,兼容性弱于自定义事件方案

扩展说明

如果你的判断需求是特定某个B类实例是否订阅了事件,而非所有B类型的实例,只需要将判断逻辑修改为比较d.Target是否等于目标B类实例即可。


内容的提问来源于stack exchange,提问作者FaultyOverflow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 18:27:07