有没有一种优雅的方式来编写这段代码?

问题描述:

我继承了一些代码,当我看着它时,它让我感到畏缩。有没有更优雅的方式来编写以下内容?有没有一种优雅的方式来编写这段代码?

Dim myItem As DTO.MyBaseClass = Nothing 
Dim myType As String = GetTypeString() 
Select Case myType 
    Case Is = "Case1" 
    myItem = Bus.BusManager(Of DTO.MyClass1).Read() 
    Case Is = "Case2" 
    myItem = Bus.BusManager(Of DTO.MyClass2).Read() 
'... etc etc for 30 lines 

是否有一种方法可以将字符串映射到类类型,然后只是像这样一行?或者类似的东西?

myItem = Bus.BusManager(Of MappingDealy(myType)).Read() 

由于BusManager是通用类型,因此必须在编译时指定传入Of <type>的类型。它不像传统参数,您可以在运行时更改。

从你列出的代码BusManager实际上做了什么还不清楚。如果它所做的只是创建一个Generic类型的实例,那么创建它的人可能不会真正理解泛型。您是否有能力修改BusManager的工作方式,还是仅限于按原样使用它?

正如@jmoreno提到的,您可以使用反射从包含类型名称的字符串中创建一个类型的实例。下面是如何将工作:

Imports System.Reflection 
Imports System.IO 

Public Class ObjectFactory 
    Private Shared Function CreateObjectFromAssembly(ByVal assembly As Assembly, ByVal typeName As String) As Object 
     ' resolve the type 
     Dim targetType As Type = assembly.GetType(typeName) 
     If targetType Is Nothing Then 
      Throw New ArgumentException("Can't load type " + typeName) 
     End If 

     ' get the default constructor and instantiate 
     Dim types(-1) As Type 
     Dim info As ConstructorInfo = targetType.GetConstructor(types) 
     Dim targetObject As Object = info.Invoke(Nothing) 
     If targetObject Is Nothing Then 
      Throw New ArgumentException("Can't instantiate type " + typeName) 
     End If 

     Return targetObject 
    End Function 

    Public Shared Function CreateObject(ByVal typeName As String) As Object 
     Return CreateObjectFromAssembly(Assembly.GetExecutingAssembly, typeName) 
    End Function 

    Public Shared Function CreateObject(ByVal typeName As String, ByVal assemblyFileName As String) As Object 
     Dim assemblyFileInfo = New FileInfo(assemblyFileName) 
     If assemblyFileInfo.Exists Then 
      Return CreateObjectFromAssembly(Reflection.Assembly.LoadFrom(assemblyFileName), typeName) 
     Else 
      Throw New ArgumentException(assemblyFileName + " cannot be found.") 
     End If 
    End Function 

End Class 

在生产应用程序,我可能会设置返回类型为所有的这些方法,我的基类或接口。只要确保你传递完整的typeName包括命名空间。

有了这一工厂类,那么你的代码的优雅版会是这个样子:

Dim myItem as DTO.MyBaseClass = ObjectFactory.CreateObject("DTO." & GetTypeString()) 
+0

哇,看起来不错,谢谢一堆! – 2011-06-02 19:32:17

首先,切勿使用Case Is =从不初始化Nothing。因此,一个快速之一将是:

Dim myItem As DTO.MyBaseClass 
Select Case GetTypeString() 
    Case "Case1" 
     myItem = Bus.BusManager(Of DTO.MyClass1).Read() 
    ' etc etc 

但由于您使用的模板,真的没有办法,除非你想使用反射,这是在稍微干净和更短的代码为代价的效率极其低下的映射它。您还可以添加Imports DTO以保存124个字符,还可以通过总线保存另外120个字符。

+1

你能详细阐述从未使用'的情况是='从不初始化为'没什么'?我对VB比较陌生。 – 2011-05-25 02:51:49

+0

'Case Is = xxx'直接等于'Case xxx',所以没有意义 - 它只是增加了语法噪音。将引用类型初始化为'Nothing'也是毫无意义的,因为这是默认情况下的。有时可以更清楚地将'布尔值'初始化为'假'和数字值为'0',但从不将类型引用为'Nothing'。 – Ryan 2011-05-25 02:53:44

+1

尽管我还不想初始化为Nothing,但他可能会这样做,以避免在赋值“变量”myItem之前使用“变量myItem”的警告。在运行时可能会产生空引用异常。如果你没有,你会得到。这个警告最糟糕的部分是,我要么通过初始化为无效(并仍然“冒险”空引用exc)来抑制它,要么就像'如果myItem IsNot Nothing Then ...' – 2011-05-25 04:22:34

没有看到更多的代码,我会建议在我的Case语句上使用Enumeration以防止出现小错误。您可以使用Factory Method来基于枚举来处理数据。