VB.NET继承场景下控制Me关键字指向对应类实例的方法咨询
MustInherit Class Person Overridable Function TableName() As String Return "Person" End Function Sub Save() DoSomething(Me) End Sub End Class Class Staff Inherits Person Overrides Function TableName() As String Return "Staff" End Function Overloads Sub Save() MyBase.Save() DoSomething(Me) End Sub End Class Sub DoSomething(o as Object) DoAnotherThing(o.TableName) End Sub
问题说明
- 现有代码运行时,无论在
Person.Save还是Staff.Save中传入DoSomething的Me,均指向运行时创建的Staff实例,调用TableName()会触发多态分派,始终返回派生类重写后的值"Staff",无法直接拿到基类Person定义的TableName返回值"Person"。 - 业务约束:
Person、Staff等类属于第三方不可修改代码,Person为抽象(MustInherit)基类,派生类包含Staff、Clients、Contacts三类;持久化层需要操作共4张表:Person表存储所有子类公共字段,每个子类对应独立表存储专属字段,需要消除大量重复的持久化逻辑。
实现方案
首先明确底层逻辑:VB.NET中引用类型的Me始终指向实际实例化的对象,不存在“修改Me指向、把Staff实例转为Person实例”的可能。你遇到的问题本质是虚方法重写后的多态分派,不需要修改原有第三方类,通过反射绕过多态即可拿到各层级类定义的表名,实现通用持久化逻辑。
具体实现思路:
- 编写独立的持久化辅助类,完全不侵入第三方代码
- 通过反射非公共实例化方式,分别获取基类、各派生类中
TableName方法的硬编码返回值,绕开虚方法的多态调用 - 收敛公共字段、子类专属字段的存表逻辑到通用方法,所有子类复用同一套逻辑
完整实现代码:
Imports System.Reflection Imports System.Runtime.CompilerServices Imports System.Runtime.Serialization ' 第三方代码原样保留,不做任何修改 Public Class DbPersistence ''' <summary> ''' 绕过多态重写,获取指定类型自身定义的TableName返回值 ''' </summary> Private Shared Function GetDeclaredTableName(targetType As Type) As String Dim tableMethod As MethodInfo = targetType.GetMethod( "TableName", BindingFlags.Public Or BindingFlags.Instance, Nothing, Type.EmptyTypes, Nothing ) ' 抽象类无法直接实例化,通过FormatterServices创建不执行构造函数的临时实例 ' 因TableName方法仅返回硬编码字符串、无实例成员依赖,该操作无副作用 Dim tempInstance As Object = FormatterServices.GetUninitializedObject(targetType) Return CStr(tableMethod.Invoke(tempInstance, Nothing)) End Function ''' <summary> ''' 保存Person层级公共字段到Person表 ''' </summary> Private Shared Sub SaveCommonFields(person As Person) Dim personTable As String = GetDeclaredTableName(GetType(Person)) ' 此处编写公共字段的SQL拼接、参数赋值、入库逻辑,固定操作Person表 DoAnotherThing(personTable) End Sub ''' <summary> ''' 保存子类专属字段到对应业务表 ''' </summary> Private Shared Sub SaveSpecificFields(Of T As Person)(instance As T) Dim specificTable As String = GetDeclaredTableName(GetType(T)) ' 此处编写子类专属字段的SQL拼接、参数赋值、入库逻辑,自动匹配对应子类表 DoAnotherThing(specificTable) End Sub ''' <summary> ''' 统一保存入口,所有子类直接调用该扩展方法即可,不需要重复写存表逻辑 ''' </summary> <Extension()> Public Sub SaveToDb(Of T As Person)(instance As T) SaveCommonFields(instance) SaveSpecificFields(instance) End Sub End Class
所有子类实例直接调用SaveToDb()即可完成双表写入,不需要分别为三个子类编写重复的存表逻辑,也不会改动第三方类的任何实现。原第三方类自带的Save方法如果不需要兼容旧逻辑可以直接忽略,避免多态导致的表名获取错误。
内容的提问来源于stack exchange,提问作者sinsi
相关产品推荐
相关产品推荐

