在过去的两天里,我尽力学习一些关于StructureMap的知识,使用我的旧项目作为具体的实现示例.我试图尽可能地简化我的问题.虽然我将在vb.net中发布我的示例,但在C#中使用示例的答案也没问题.
该项目包括一个名为IDatabase的接口,它将自身连接到数据库.重要的部分看起来像这样.
Public Interface IDatabase
Function Connect(ByVal ConnectionSettings As ConnectionSettings) As Boolean
ReadOnly Property ConnectionOpen As Boolean
[... more functions...]
End Interface
Public Class MSSQLConnection
Implements IDatabase
Public Function Connect(ByVal ConnectionSettings As ConnectionSettings) As Boolean Implements IDatabase.Connect
[... Implementation ...]
End Function
[... more implementations...]
End Class
ConnectionSettings是一种结构,包含连接数据库所需的所有信息.
我想打开数据库连接一次,并将其用于项目中的每个连接,所以我在ObjectFactory中注册一个实例.
dim foo = ObjectFactory.GetInstance(Of MSSQLConnection)()
dim bar as ConnectionSettings
foo.connect(bar)
ObjectFactory.Configure(Sub(x) x.For(Of IDatabase).Use(foo))
直到这一部分,一切都像魅力一样.现在,我得到了一个点,我需要一个额外的IDatabase实例,因为它们连接到第二个数据库.
Public Class ExampleClass
Public Sub New(ByVal SameOldDatabase as IDatabase, ByVal NewDatabase as IDatabase)
[...] Magic happens here [...]
End Sub
End Class
我希望第二个IDatabase的行为与第一个类似.我希望它使用具体的单个实例,并希望将其连接到另一个数据库,调用Connect与不同的ConnectionSettings.
问题是:虽然我很确定它是可能的,但我最初的想法是使用替代构造函数参数注册ExampleClass,我实际上想要在不注册ExampleClass的情况下这样做.这可能涉及更多配置,但我不知道如何做到这一点.
所以,基本上,它归结为这个问题:
我如何配置ObjectFactory,使自动装配始终使用对象Database1为第一个IDatabase参数调用构造函数,并为第二个对象Database2调用对象Database2(如果有的话?)
最佳答案 您可以使用RegistrationConvention和第二个连接的命名实例.考虑以下quick’n’dirty代码:
Imports StructureMap.Graph
Imports StructureMap.Configuration.DSL
Imports StructureMap
Public Module Module1
Public Interface IDatabase
Property ConString As String
End Interface
Public Class MSSQLConnection
Implements IDatabase
Public Property ConString() As String Implements IDatabase.ConString
End Class
Public Class ExampleClass
Public Sub New(ByVal SameOldDatabase As IDatabase, ByVal NewDatabase As IDatabase)
Console.WriteLine(SameOldDatabase.ConString)
Console.WriteLine(NewDatabase.ConString)
End Sub
End Class
Public Class SecondDatabaseConstructorIsAnotherOne
Implements IRegistrationConvention
Public Sub Process(ByVal type As Type, ByVal registry As Registry) Implements IRegistrationConvention.Process
Dim ctor = type.GetConstructors().FirstOrDefault(Function(c) c.GetParameters().Where(Function(p) p.ParameterType = GetType(IDatabase)).Count = 2)
If Not ctor Is Nothing Then
Dim parameter = New List(Of Object)
Dim second = False
For Each o In ctor.GetParameters()
If o.ParameterType = GetType(IDatabase) AndAlso second Then
parameter.Add(ObjectFactory.GetNamedInstance(Of IDatabase)("secondDB"))
Else
If o.ParameterType = GetType(IDatabase) Then second = True
parameter.Add(ObjectFactory.GetInstance(o.ParameterType))
End If
Next
registry.For(type).Use(Function(context) Activator.CreateInstance(type, parameter.ToArray()))
End If
End Sub
End Class
Sub Main()
Dim con1 = New MSSQLConnection() With {.ConString = "ConnectToFirstDatabase"}
Dim con2 = New MSSQLConnection() With {.ConString = "ConnectToSecondDatabase"}
ObjectFactory.Initialize(Sub(init)
init.For(Of IDatabase).Use(con1)
init.For(Of IDatabase).Add(con2).Named("secondDB")
End Sub)
ObjectFactory.Configure(Sub(config)
config.Scan(Sub(scan)
scan.TheCallingAssembly()
scan.Convention(Of SecondDatabaseConstructorIsAnotherOne)()
End Sub)
End Sub)
ObjectFactory.GetInstance(Of ExampleClass)()
Console.ReadLine()
End Sub
End Module
你会明白的.