c# – StructureMap使用相同接口的两个不同实例进行自动装配

在过去的两天里,我尽力学习一些关于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

你会明白的.

点赞