VB.NET如何通过动态创建窗体名称简化重复代码?
如何在VB.NET中通过动态类名创建窗体实例简化多分支代码?
我目前在VB.NET里写了一段右键菜单的点击事件代码,通过一堆If-Else分支来匹配不同的DataGridView,创建对应的RightClickMenuDgv_1、RightClickMenuDgv_2这类窗体实例。但这种写法扩展性太差,新增一个DataGridView就得加新的分支,想通过动态拼接类名的方式来简化代码。之前查过反射和Activator.CreateInstance,但没找到贴合场景的示例,希望能实现类似直接用DbNr动态生成类名创建实例的效果。
现有冗余代码
Private Sub ChangeToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ChangeToolStripMenuItem.Click Dim DbNr As Integer = Strings.Right(DataGridName.Name, 1) If DataGridName.Name = Dgv_1.Name Then Dim Obj As New RightClickMenuDgv_1("Change", ValueMaster, ValueIdDgv(DbNr)) If Obj.ShowDialog() = DialogResult.OK Then RefreshDataGrids("Change") ElseIf DataGridName.Name = Dgv_2.Name Then Dim Obj As New RightClickMenuDgv_2("Change", ValueMaster, ValueIdDgv(DbNr)) If Obj.ShowDialog() = DialogResult.OK Then RefreshDataGrids("Change") ElseIf DataGridName.Name = Dgv_3.Name Then Dim Obj As New RightClickMenuDgv_3("Change", ValueMaster, ValueIdDgv(DbNr)) If Obj.ShowDialog() = DialogResult.OK Then RefreshDataGrids("Change") ElseIf DataGridName.Name = Dgv_4.Name Then Dim Obj As New RightClickMenuDgv_4("Change", ValueMaster, ValueIdDgv(DbNr)) If Obj.ShowDialog() = DialogResult.OK Then RefreshDataGrids("Change") End If End Sub
期望实现的简化写法
Private Sub ChangeToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ChangeToolStripMenuItem.Click Dim DbNr As Integer = Strings.Right(DataGridName.Name, 1) Dim Obj As New RightClickMenuDgv_(DbNr)("Change", ValueMaster, ValueIdDgv(DbNr)) If Obj.ShowDialog() = DialogResult.OK Then RefreshDataGrids("Change") End Sub
解决方案:利用反射实现动态创建实例
要实现你想要的效果,需要借助.NET的反射机制,通过拼接类名获取类型,再用Activator.CreateInstance创建实例。下面是具体的实现步骤和代码:
1. 确保类的命名空间正确
首先要确认所有RightClickMenuDgv_N类都在同一个命名空间下(比如你的项目默认命名空间是YourAppNamespace),否则需要调整类名的拼接逻辑。
2. 完整的简化代码
Private Sub ChangeToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ChangeToolStripMenuItem.Click Dim DbNr As Integer = Strings.Right(DataGridName.Name, 1) ' 拼接完整的类名(替换成你的实际命名空间) Dim className As String = $"YourAppNamespace.RightClickMenuDgv_{DbNr}" ' 获取类的Type Dim formType As Type = Type.GetType(className) If formType IsNot Nothing Then ' 构造函数的参数列表 Dim constructorParams As Object() = {"Change", ValueMaster, ValueIdDgv(DbNr)} ' 创建窗体实例 Dim obj As Form = DirectCast(Activator.CreateInstance(formType, constructorParams), Form) If obj.ShowDialog() = DialogResult.OK Then RefreshDataGrids("Change") End If Else ' 处理类不存在的异常情况 MessageBox.Show($"未找到对应的窗体类:RightClickMenuDgv_{DbNr}") End If End Sub
关键细节说明
- 类名拼接:一定要包含命名空间,否则
Type.GetType可能找不到对应的类型(如果类不在默认命名空间下的话)。 - 类型转换:
Activator.CreateInstance返回的是Object类型,需要转成Form(或者你的窗体基类,如果这些右键菜单窗体有共同基类的话),这样才能调用ShowDialog方法。 - 异常处理:添加了
formType IsNot Nothing的判断,避免因为类名拼写错误或不存在导致的运行时异常。
进阶优化:使用基类或接口
如果所有RightClickMenuDgv_N窗体都有相同的行为,可以定义一个基类(比如BaseRightClickMenuForm),然后让所有窗体继承这个基类。这样类型转换的时候可以直接转成基类,代码更严谨:
' 定义基类 Public Class BaseRightClickMenuForm Inherits Form ' 可以在这里定义共同的属性或方法 Public Sub New(operation As String, master As Object, id As Object) ' 基类构造逻辑 End Sub End Class ' 每个右键菜单窗体继承基类 Public Class RightClickMenuDgv_1 Inherits BaseRightClickMenuForm ' 子类构造函数 Public Sub New(operation As String, master As Object, id As Object) MyBase.New(operation, master, id) ' 子类特有逻辑 End Sub End Class
然后在创建实例的时候直接转成基类:
Dim obj As BaseRightClickMenuForm = DirectCast(Activator.CreateInstance(formType, constructorParams), BaseRightClickMenuForm)
这样代码的可维护性会更高,也能避免一些类型转换的潜在问题。
内容的提问来源于stack exchange,提问作者Miguel Terlaak
相关产品推荐
相关产品推荐

