Winforms 将依赖注入类与容器传递到应用程序启动WinForm

Winforms 将依赖注入类与容器传递到应用程序启动WinForm,winforms,dependency-injection,ioc-container,n-tier-architecture,compositionroot,Winforms,Dependency Injection,Ioc Container,N Tier Architecture,Compositionroot,我正在开发一个WinForms应用程序,它被配置为典型的3层UI、BLL和DAL。我创建了一个单独的项目作为启动项目。还创建了另一个项目,作为自制的依赖项注入容器,用于执行所有依赖项注入设置。自制的依赖注入容器由启动项目实例化,然后将实例化的对象传递给第一个WinForm 自制的依赖项注入容器实现如下所示: public class AppDependencyInjection { public BLL.DataServices.DepartmentDataServices BllDep

我正在开发一个WinForms应用程序,它被配置为典型的3层UI、BLL和DAL。我创建了一个单独的项目作为启动项目。还创建了另一个项目,作为自制的依赖项注入容器,用于执行所有依赖项注入设置。自制的依赖注入容器由启动项目实例化,然后将实例化的对象传递给第一个WinForm

自制的依赖项注入容器实现如下所示:

public class AppDependencyInjection
{
    public BLL.DataServices.DepartmentDataServices BllDeptDataServices = null;
    private DAL.DataServices.DepartmentDataServices DalDeptDataServices = null;

    public BLL.ReportServices.RequestReports BllRequestReports = null;
    private DAL.ReportServices.RequestReports DalRequestReports = null;

    public AppDependencyInjection()
    {
        DalDeptDataServices = new DAL.DataServices.DepartmentDataServices();
        BllDeptDataServices = new BLL.DataServices.DepartmentDataServices(DalDeptDataServices);//inject actual implementations

        DalRequestReports = new DAL.ReportServices.RequestReports();
        BllRequestReports = new BLL.ReportServices.RequestReports(DalRequestReports);//inject actual implementations
    }
}
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    //instantiate dependent classes and inject into class constructors 
    AppDependencyInjection aDI = new AppDependencyInjection(); 

    //Pass objects with injected dependencies into app startup WinForm
    Application.Run(new MDIS.WinForms.UI.Form1(aDI.BllDeptDataServices, aDI.BllRequestReports));
}
启动项目如下所示:

public class AppDependencyInjection
{
    public BLL.DataServices.DepartmentDataServices BllDeptDataServices = null;
    private DAL.DataServices.DepartmentDataServices DalDeptDataServices = null;

    public BLL.ReportServices.RequestReports BllRequestReports = null;
    private DAL.ReportServices.RequestReports DalRequestReports = null;

    public AppDependencyInjection()
    {
        DalDeptDataServices = new DAL.DataServices.DepartmentDataServices();
        BllDeptDataServices = new BLL.DataServices.DepartmentDataServices(DalDeptDataServices);//inject actual implementations

        DalRequestReports = new DAL.ReportServices.RequestReports();
        BllRequestReports = new BLL.ReportServices.RequestReports(DalRequestReports);//inject actual implementations
    }
}
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    //instantiate dependent classes and inject into class constructors 
    AppDependencyInjection aDI = new AppDependencyInjection(); 

    //Pass objects with injected dependencies into app startup WinForm
    Application.Run(new MDIS.WinForms.UI.Form1(aDI.BllDeptDataServices, aDI.BllRequestReports));
}
接收WinForm的实例与注入的对象如下所示:

public Form1(BLL.DataServices.DepartmentDataServices aBllDeptDataServices,
             BLL.ReportServices.RequestReports aBllRequestReports)
{
    InitializeComponent();
    BllDeptDataServices = aBllDeptDataServices;
    BllRequestReports = aBllRequestReports;
}
WinForm在以下两个按钮单击事件中使用注入的对象:

private void btnGetAllDepartments_Click(object sender, EventArgs e)
{
    List<DepartmentDto> aDepartmentDtoList = BllDeptDataServices.GetAllDepartments();
}

private void btnGetAllRequests_Click(object sender, EventArgs e)
{
    List<RequestDetailDto> aRequestDetailDtoList = BllRequestReports.GetAllRequestDetail();
}
private void btnGetAllDepartments\u单击(对象发送者,事件参数e)
{
List aDepartmentDtoList=BllDeptDataServices.GetAllDepartments();
}
私有void btnGetAllRequests\u单击(对象发送者,事件参数e)
{
List aRequestDetailDtoList=BllRequestReports.GetAllRequestDetail();
}
这项工作目前没有太大问题,因为我只传递了2个注入对象。但是这似乎是个问题,如果对象的数量增加到5个以上,那么我将向启动WinForm传递5个以上的参数。如果我决定将名为AppDependencyInjection的自制依赖项注入容器传递到WinForm,而不是单个注入类,那么我可以将要传递的参数限制为一个。如果我这样做,它将使表示层依赖于自制的依赖项注入项目,从而使表示层同时依赖于BLL和依赖项注入项目。这可以接受吗?我还可以做些什么来适应应用程序中依赖注入类的未来增长

但是这似乎是个问题,如果对象的数量增加到5个以上,那么我将向启动WinForm传递5个以上的参数

如果您注入了5个以上的依赖项,这表明您的类做得太多了;有太多的责任。这违反了法律。如果发生这种情况,你开始考虑将你的类分成多个更小的类。例如,您可能能够将某些依赖项及其逻辑分组到表单中,或者可以将表单拆分为多个较小的组件/控件。记住:关键是构图

我决定将名为AppDependencyInjection的自制依赖注入容器传递到WinForm,而不是单个注入类

你不应该这样做。这是一个称为服务定位器的模式,它具有以下特性。坚持依赖注入,如果这变得麻烦,只注入类直接需要的内容,例如,因为类有太多依赖项,所以代码/设计有问题(例如SRP冲突)

还请注意,不建议创建自己的DI库。这样的库将缺少可用DI库提供的许多重要特性,但与使用(即手动连接对象图)相比没有优势。您将失去编译时支持,而得不到任何回报

当你的应用程序很小的时候,你应该从纯DI开始,一旦你的应用程序和你的DI配置增长到维护你的组成根变得笨重的时候,你可以考虑切换到一个已建立的DI库。


在你看来,你似乎在某个中间。尽管依赖项似乎来自一个常见的“依赖项注入器”,但您仍然需要手动连接类,而无需进行反射(即显式调用构造函数)。请注意,一旦开始使用反射,就可以使用已知的DI库了。

谢谢Steven。我将按照您的建议调查聚合服务。我的项目中有十几个实体模型,每个模型都需要应用存储库操作,就像我在示例中使用的Department one一样。听起来像是使用聚合服务,我可以将其中的几个组合在一起,这样就不必为每个DAL实现设置注入。