创建类型实例的意外行为

时间:2013-09-13 13:55:12

标签: .net vb.net type-conversion structuremap

我有一个大型Windows窗体应用程序,其中包含最终用户可以使用的大量报表/工作流程。 我正在使用StructureMap for IoC / DI,.Net 3.5

每个报告/路线的元数据由数据库中的行表示。标准的东西,如唯一的rowID,报告名称,几个描述性句子。

目前我有一个班级负责启动每个报告。这是一个大规模的Case语句,如下所示:

Public Sub LaunchSomething(launchRequest as LaunchItemInfo)
  Dim cmd as ICommand
  Select Case launchRequest.UniqueId
  Case 1
    cmd = New Reports.AccountsPayable.PrintChecksCommand
  Case 2
    cmd = New SomeOtherCommandClass
  ..
  Case 400
    cmd = New Report400Class
  End Select

    AppController.Commands.Invoke(cmd)
  End Sub

我真的希望能够使用这样的代码:

Public Sub LaunchSomething(launchRequest as LaunchItemInfo)
  Dim cmd as ICommand
  Dim typ as Type
  typ = Type.GetType(launchRequest.ReportClassName, launchRequest.FileContainingReportClass)
  cmd = Activator.CreateInstance(typ)
  AppController.Commands.Invoke(cmd)
End Sub

这些是支持接口&我正在使用的课程。 ICommand只是一个标记界面

Public Interface ICommand
End Interface

Public Interface ICommandHandler(Of C As ICommand)
    Sub Handle(cmd As C)
End Interface

Public Class PrintChecksCommand
    Implements ICommand
End Class

AppController.Commands是一个CommandInvoker,Invoke方法如下所示:

Public Sub Invoke(Of C As ICommand)(ByVal command As C)
  Dim handlers as Generic.IList(Of IcommandHandler(Of C))
  handlers = ObjectFactory.GetAllInstances(Of ICommandHandler(Of C))()
  For each h as ICommandHandler(Of C) in handlers
    h.Handle(command)
 Next
 End Sub

当我使用400+ Case语句的原始代码时,处理程序集合正确包含1个项目。所以我知道我的结构图注册表设置正确。

当我尝试使用Activator.CreateInstance所需的代码时,处理程序集合为空。

据我在调试器中可以看出,当使用2种方法中的任何一种创建{{1}时,我在ICommand上传递了一个相同类型的CommandInvoker传递给Invoke方法}}

我需要更改哪些内容才能使用PrintChecksCommand

1 个答案:

答案 0 :(得分:1)

解决这个问题的技巧是将Generics添加到ICommand接口,并利用CommandInvoker中的额外信息。

接口/类现在看起来像这样:

Public Interface ICommand(Of T)  
End Interface  

Public Interface ICommandHandler(Of T as ICommand(Of T))
  Sub Handle(cmd as T)  
End Interface

Public Interface ICommandInvoker  
    Sub Invoke(Of T As ICommand(Of T))(ByVal command As ICommand(Of T))  
End Interface  

Public Class CommandInvoker  
      Implements ICommandInvoker  
    Public Sub Invoke(Of T As ICommand(Of T))(command As ICommand(Of T)) Implements ICommandInvoker.Invoke
    Dim handlers As Generic.IList(Of ICommandHandler(Of T)) = Nothing  
    handlers = ioc.GetAllInstances(Of ICommandHandler(Of T))()  
    For Each h As ICommandHandler(Of T) In handlers  
        h.Handle(command)  
    Next  
    End Sub  
End Class

Public Class DoSomethingCommand
    Implements ICommand(Of DoSomethingCommand)
    Public Sub New()
    End Sub
End Class

Public Class SomethingHandler
    Implements ICommandHandler(Of DoSomethingCommand)

    Public Sub New()
    End Sub

    Public Sub Handle(cmd As DoSomethingCommand) Implements ICommandHandler(Of DoSomethingCommand).Handle
    End Sub
End Class