如何创建「类已初始化」事件?是否存在原生类实例创建事件?
类实例完全初始化后自动触发内部封装事件的实现方案
问题根因
在Sub New构造方法内直接触发事件时拿到Nothing实例的核心原因是:构造函数执行阶段,实例尚未走完完整的初始化流程(包括继承链上的子类字段赋值、构造函数链执行等),此时对外暴露的实例引用是不完整的;而在New实例化代码之后手动触发事件的写法,会把触发逻辑散落在所有实例化调用点,破坏类的封装性,不符合面向对象设计要求。
推荐实现:工厂方法收归实例化入口
这是最符合OOD原则、无副作用的实现方式:
- 将类的构造函数修改为私有访问级别,禁止外部直接通过
New创建实例 - 在类内部提供共享(
Shared)工厂方法作为唯一的实例化入口,统一完成实例创建、事件触发逻辑,所有触发逻辑完全封装在类内部,外部调用无感知 - 工厂方法内是在实例走完完整构造流程之后才触发事件,此时事件处理程序拿到的实例是完全初始化后的可用状态,不会出现
Nothing问题
代码示例:
Public Class BusinessEntity ' 定义实例初始化完成事件 Public Event InstanceInitialized(sender As Object, args As EventArgs) ' 私有构造函数,阻断外部直接New的入口 Private Sub New() ' 此处编写所有类内部初始化逻辑:字段赋值、资源加载、配置读取等 End Sub ' 对外暴露的唯一实例化入口 Public Shared Function CreateInstance() As BusinessEntity Dim newInstance As New BusinessEntity() ' 实例已完成全部构造流程,此时触发事件 RaiseEvent newInstance.InstanceInitialized(newInstance, EventArgs.Empty) Return newInstance End Function End Class
外部调用时只需要通过工厂方法获取实例即可,不需要编写任何额外的事件触发代码:
' 外部调用示例 Dim entity = BusinessEntity.CreateInstance() AddHandler entity.InstanceInitialized, Sub(s, e) ' 此处s就是完整初始化后的实例,不会为Nothing Console.WriteLine($"实例初始化完成:{s.GetType().Name}") End Sub
兼容旧代码的临时方案(不推荐生产环境使用)
如果已有大量代码直接通过New实例化类、暂时无法全量改造为工厂方法,可以将事件触发逻辑投递到线程队列,等当前构造函数执行栈释放、实例完全初始化后再执行触发逻辑。但该方案存在时序竞态风险,实例创建后如果立刻访问依赖事件初始化的成员,可能出现异常。
Public Class BusinessEntity Public Event InstanceInitialized(sender As Object, args As EventArgs) Public Sub New() ' 内部初始化逻辑 ThreadPool.QueueUserWorkItem(Sub() RaiseEvent InstanceInitialized(Me, EventArgs.Empty) End Sub) End Sub End Class
继承场景注意事项
如果类处于继承体系中,禁止在基类构造函数内触发初始化完成事件:子类的字段初始化、构造逻辑是在基类构造函数执行完成后才会运行,此时触发事件拿到的子类实例是未完成初始化的状态,必然出现成员为空的问题。这种场景下统一用工厂方法实现即可规避问题。
内容的提问来源于stack exchange,提问作者user1500403
相关产品推荐
相关产品推荐

