【问题标题】:there is any way to instantiate a new class based on enum?有什么方法可以基于枚举实例化一个新类?
【发布时间】:2014-06-10 15:42:16
【问题描述】:

有什么方法可以通过反射实例化一个基于枚举的新类?
基本上我想删除 Select Case。我有很多 Enum 和建设者....

例如:

Public MustInherit Class GeneralClass
    '...

    Enum GeneralClassType
         A = 1
         B = 2
    End Enum

    Public Shared Function BuildClass(Val as Integer, ParamArray par() as Object) as GeneralClass
        Dim NewObject as GeneralClass = Nothing

        Select Case Ctype(Val, GeneralClassType)
              Case GeneralClassType.A
                   NewObject = new A 

              Case GeneralClassType.B
                   NewObject = new B

              Case else
                   throw new exception("invalid type.")

        end select

        NewObject.setPar(par)
        return NewObject
    end function
End Class

Public Class A
    Inherits GeneralClass
    '...
End Class

Public Class B
    Inherits GeneralClass
    '...
End Class

BuildClass 函数基于从数据库获取的类型和参数构建类。 但我需要有案例来创建一个类型的新实例。

我知道我可以通过反射来实例化一个类,但前提是你知道最终类型。 没有办法做到这一点,比如将类名保存在数据库中?

 public function InstantiateClass(of T)() as T
     Dim NewObject as GeneralClass = GetType(T).GetConstructor(New Type() {}).Invoke(New Object() {})
     return NewObject
 end class

我可以得到类似的东西

Dim Var1 as GeneralClass = InstantiateClass(of A)()

并在 Build 函数中使用此实例。但在这里我需要知道类型 A



BaseTest 示例,使用枚举名称。

Public Class Form1

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim BaseFlag As Integer = 2
        Dim BaseName As String = "Create a class from enum"


        Dim T As BaseTest = BaseTest.Build(BaseFlag, BaseName)
        MsgBox(T.GetClassTypeName)
    End Sub

End Class

Public MustInherit Class BaseTest
    Protected Name As String

    Enum TestType
        TestA = 1
        TestB = 2
        TestC = 3
    End Enum

    Public Function GetClassTypeName() As String
        Return String.Concat(Name, ". The final class is: ", Me.GetType.FullName, "")
    End Function

    Public Shared Function Build(BaseFlag As Integer, Name As String) As BaseTest
        Dim NS As String = GetType(BaseTest).FullName
        Dim Index As Integer = NS.LastIndexOf(".") + 1
        NS = NS.Substring(0, Index)

        Dim ClassType As String = CType(BaseFlag, TestType).ToString()
        Dim Test As BaseTest = Activator.CreateInstance(Type.GetType(NS & ClassType))

        Test.Name = Name
        Return Test
    End Function
End Class

Public Class TestB
    Inherits BaseTest

End Class

【问题讨论】:

  • 进行反射以节省打字可能并不总是正确的决定。如果你有很多重复的代码,你应该重新考虑你的设计。反思似乎更容易。从长远来看,您希望有很多维护噩梦。当然,除非你证明了这一举动是合理的。
  • 我正在使用反射,因为我不知道另一种方法可以做到这一点。关键是,很快我将在我的基地中为所有标志提供大量枚举。此标志确定一种或另一种流动方式。所以为了避免很多类有相同的代码,a做了一些泛型类,具体的类针对具体的方式,减少了很多类的数量和维护。旧代码充满了“Dim ob as New EspecificClass”,没有超类,而不是调用一些不特定的方法。好吧,现在我只需要担心构建器而不是所有“Dim ob as New EspecificClass” .
  • 您似乎正在分支工作流程,即有一组恒定(或有限,更好地说)步骤,而它们之间的链接是动态的。您是否考虑过表格驱动设计?
  • 以前从不使用“表驱动设计”,但我会检查一下。谢谢。
  • 您可能会发现这些链接很有用:codeproject.com/Articles/42732/Table-driven-Approachen.wikipedia.org/wiki/Control_table,让您了解术语(以及进一步搜索的想法)。

标签: vb.net reflection enums instantiation


【解决方案1】:

第一步是弄清楚如何通过反射来创建一个给定类名作为字符串的对象实例。这是一种方法的示例:

Dim o As Object = Activator.CreateInstance(Type.GetType("MyNameSpace.A"))

一旦你完成了这项工作,你需要做的就是获取枚举值的字符串名称。为此,您需要做的就是在枚举对象上调用ToString 方法,例如,在您的情况下:

Dim className As String = CType(Val, GeneralClassType).ToString()

一旦你有了它,你可以简单地将类名连接到命名空间来创建对象:

Dim o As Object = Activator.CreateInstance(Type.GetType("MyNameSpace." & className))

您发布的示例是类型安全的,而像这样使用反射则不是。此外,反射可能会慢一些。您需要根据自己的具体情况决定是否值得放弃这种类型安全性和效率。

【讨论】:

  • 我将对其进行测试并稍后发布。谢谢!
  • 事实上这有效。类名必须是枚举的名称,但可以正常工作!我将用这个答案更新问题。
  • “类名必须有枚举的名字”。现在每个特定操作都需要一个枚举和类。那就是我正在寻找的,无需维护所有代码。只是特定的类和你的枚举。
猜你喜欢
  • 2019-12-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-10
  • 1970-01-01
  • 1970-01-01
  • 2014-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多