关于依赖注入:WinForms应用中Unity Container中加载依赖

Loading dependencies in Unity Container in WinForms application

Solution

这就是部分解决方案的样子。

由于我在 Winforms 环境中使用 Onion 架构,因此我拥有 UI、基础设施和核心层。所有层都使用依赖注入松散耦合。我想要实现的是,每当一个表格来自例如帐户表单(类库)已加载,所有依赖项都应加载到 UnityContainer 中,即已注册的类型。这些依赖项是核心和基础架构项目中存在的接口和实现。

我的困惑是我应该在哪里编写代码来注册依赖项?这个应用程序的组合根是什么?请注意,来自例如的表格Accounts Forms、HR Forms 等都是使用 Main Windows 应用程序中的反射加载的,该应用程序仅引用 Base Forms Project。

根据 Eben Roux 的建议

这是我在加载程序集时执行连线代码的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 Dim assemb As System.Reflection.Assembly    
              ...
              ...
 If assemb IsNot Nothing Then
     Dim type As Type = GetType(IDependencyWiring)
     Dim modules As List(Of Type) = assemb.GetTypes().Where(Function(p) type.IsAssignableFrom(p) AndAlso p.IsClass).ToList()

     For Each [module] As Type In modules
         Dim argTypes As Type() = New Type() {}
         Dim cInfo As ConstructorInfo = [module].GetConstructor(argTypes)
         Dim dependencyWiringModule As IDependencyWiring = DirectCast(cInfo.Invoke(Nothing), IDependencyWiring)
         dependencyWiringModule.WireUp()
     Next
 End If

这里是具有 WireUp 方法的模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Public Class AccountModule : Implements IDependencyWiring

    Private Shared Container As IUnityContainer

    Public Sub New()
        Container = New UnityContainer()
    End Sub

    Public Sub WireUp() Implements IDependencyWiring.WireUp
        Container.RegisterType(Of IInterface1, Class1)()
        Container.RegisterType(Of IInterface2, Class2)()
        Container.RegisterType(Of IInterface3, Class3)()
        Container.RegisterType(Of IInterface4, Class4)()
    End Sub

    Public Shared Function Resolve(typeToResolve As Type) As Object
        Return Container.Resolve(typeToResolve.GetType())()
    End Function
End Class

所以我现在的问题是:

  • 将 Container 存储为 Shared 并使用它通过 Resolve 方法解决依赖关系是否正确?
  • 我封装容器的 Resolve 行为的方式存在问题。什么是正确的语法?我不想在每个表单上引用 Unity 以便能够调用 Resolve 方法,所以我封装了我自己的 Resolve 方法。通过这种方式,如果我想更改 IOC 容器而不更改容器引用,我可以很容易地用另一个替换 AccountModule。

  • 使用这种类型的插件架构,您实际上会得到多个组合根(各种)。很可能会有一些依赖关系,只有您的插件知道并且可以连接。

    因此,您的架构的一部分应该是插件的加载。这可能发生在主应用程序的连线位(组合根)中的某个位置,这将使每个插件都有机会执行其连线。

    由于并非所有插件都需要接线,因此可以通过使用单独的接口来明确说明:

    1
    2
    3
    4
    public interface IDependencyWiring
    {
        public void WireUp(IDependencyContainer container); // <-- changed to conform to update
    }

    然后在主成分根中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    foreach (var plugin in plugins)
    {
        var wiring = plugin as IDependencyWiring;

        if (wiring != null)
        {
            wiring.WireUp(myContainer);
        }
    }

    我希望这是有道理的。

    更新:

    首先我会使用安全演员表。 TryCast 在 VB.NET 世界中。您可以通过使用自己的界面,使用依赖反转从实际插件中摆脱 Unity。像这样:

    1
    2
    3
    4
    5
    6
    7
    public interface IDependencyContainer
    {
        void Register(Type type);
        void Register< T >();
        void Resolve(Type type);
        void Resolve< T >();
    }

    好吧,你会添加你需要的东西。然后像我在顶部 public void WireUp(IContainer container);.

    上所做的那样,在连线中传递对容器的引用

    Resolve 行为有些问题,因为您似乎正朝着服务定位器方向前进。尝试通过使用构造函数(或其他)注入来尽可能多地由容器完成解析。当然,这对 Singleton 组件很有效。对于瞬态的,我宁愿使用一个接收 IDependencyContainer 实例的单例工厂(这样它也将被注册),它会为你解决(实际上是创建)。