-1

我从不在应用程序中使用依赖注入。我浏览了几篇关于依赖注入的文章,发现这个概念很有趣,但相信在现实生活中很难实现。现在我想在我的 win 表单应用程序中实现依赖注入。

我们公司目前与许多航运公司合作,如 UPS、Fedex、Purolator 等,但未来他们计划与许多其他航运公司合作。我为 UPS、Fedex、Purolator 等所有运输公司开发了单独的独立类库项目,并将这些 dll 包含到我们的主窗体应用程序中。问题是很多时候我们在我们的代码中硬编码一些东西,比如国家代码等。

例如,我有一个表格,其中有 4 个按钮。就像这些按钮是“使用 UPS WorldShip 运送”,另一个按钮称为“使用 UPS WebAPI 运送”,另一个按钮称为“使用 FedEX 桌面应用程序运送”,最后一个按钮称为“使用 Fedex WebAPI 运送”。

当用户单击 UPS WorldShip 按钮时,会在文件夹中生成一个平面文件。当用户单击 UPS WebAPI 按钮时,请求会转到 UPS 站点。

当用户单击 FedEX WinApps 按钮时,会在文件夹中生成一个平面文件。当用户单击 FedEX WebAPI 按钮时,请求会转到 FedEx 站点。

所以当用户点击任何按钮时我现在做什么,然后我调用 dll 中存在的特定函数来完成任务。

最后一切都很好,但问题是当我们公司开始与另一家新的航运公司合作时,我必须为该公司创建另一个类库。

我说我从来没有在我的应用程序中使用过 DI,也没有经验。所以有人指导我如何处理我与 DI 的情况,因此当一家新的航运公司加入时,我不必编写任何额外的代码。所以请指导我如何在我的应用程序中实现 DI,并指导我如何使用示例 DI 代码处理我的情况以获得指导。

我的第二阶段问题

1) 什么时候需要调用 InitializeKernel() 函数?当应用程序加载或表单加载时

2)我不熟悉ninject所以我只是不明白这行代码的含义是什么

.Configure((b, c) => b.InTransientScope().Named(c.Name)));

3) c.Name 会返回什么?

4)我发现没有配置文件条目。ninject 不需要像 unity DI 这样的配置文件条目?

你给的代码看起来很专业。如果可能,请回答我的所有观点。

最后告诉我有没有可供 ninject 学习 DI 和 ninject 代码使用的 pdf。

谢谢

我的第三阶段问题

非常抱歉,您对 InitializeKernel() 声明一次。

你说 Ninject 只支持流畅的配置,然后可能会出现问题,因为当新的航运公司加入时,我必须在这个块中更改代码,比如

using(var kernel = InitializeKernel())     
{
    // 4.1 resolve delivery services by names
    var upsWorldShip = kernel.Get<IShippingCompanyService>("ShippingUpsWorldShip");
    var fedExDesktopApps = kernel.Get<IShippingCompanyService>("ShippingFedExDesktopApps");


    var PurolatorExDesktopApps = kernel.Get<IShippingCompanyService>("PurolatorFedExDesktopApps");

    // 4.2 delivery processing
    upsWorldShip.Delivery();
    fedExDesktopApps.Delivery();

    // 5 PROFIT!
}

所以在这里我需要添加这一行

var PurolatorExDesktopApps = kernel.Get<IShippingCompanyService>  ("PurolatorFedExDesktopApps");

问题是每当添加新的与运输相关的 dll 时,我必须在上面的块中添加一行代码....这是不可取的。

如果我可以在配置文件中添加所有 dll 的相关信息并从那里加载和实例化所有 dll 中的所有类,那就更好了。所以我正在寻找你的建议。谢谢

4

2 回答 2

2

似乎您要求按约定进行配置。这意味着您确定应该共享公共配置的组件组,然后在阅读更多信息后在单个语句中指定该配置

在实践中,这意味着您将所有具有选定功能的库“交付”部署到项目中的“特殊”位置,并从“特殊”接口继承所有实现。最后,制作 DI 容器以找到它们并为您配置所有内容。

定义约定

这是一个简单的示例,如何使用Ninject.Extensions.Conventions.

注意评论

// 1 define "delivery" interface
interface IShippingCompanyService
{
    void Delivery();
}

// 2.1 — first assembly "Ups.Services.dll"
public class ShippingUpsWorldShip : IShippingCompanyService
{
    public void Delivery()
    {
        "Ship with UPS WorldShip".Dump();
    }
}

// 2.2 — first assembly "FedEx.Services.dll"
public class ShippingFedExDesktopApps : IShippingCompanyService
{
    public void Delivery()
    {
        "Ship with FedEX Desktop Apps".Dump();
    }
}

定义配置

使用 Ninject Kernel 构建配置(StandardKernel在本例中)

// 3 kernel configuration
public static IKernel InitializeKernel() 
{ 
    var kernel = new StandardKernel();

    kernel.Bind(x => x
         // 3.1 search in current assembly
        .FromThisAssembly()
            .SelectAllClasses() // 3.2 select all classes implement "special" interface
            .InheritedFrom<IShippingCompanyService>()
        // 3.3 search all assemblies by wildcards
        .Join.FromAssembliesMatching("./*Services.dll")
            .SelectAllClasses() // 3.2 select all classes implement special interface
            .InheritedFrom<IShippingCompanyService>()
        // 3.4 bind to "special" interface
        .BindAllInterfaces()
        // 3.5 configure lifetime management and dependency name
        .Configure((b, c) => 
            b.InTransientScope().Named(c.Name)));

    return kernel; 
} 

如何解决依赖关系

应用程序的组合根目录按名称解析交付服务

// 4 from your Compositon Root ...
using(var kernel = InitializeKernel())     
{
    // 4.1 resolve delivery services by names
    var upsWorldShip = kernel.Get<IShippingCompanyService>("ShippingUpsWorldShip");
    var fedExDesktopApps = kernel.Get<IShippingCompanyService>("ShippingFedExDesktopApps");

    // 4.2 delivery processing
    upsWorldShip.Delivery();
    fedExDesktopApps.Delivery();

    // 5 PROFIT!
}

此处提供的所有资源

概括

按惯例配置是许多项目中已经采用的非常有用的方法。不过,我建议您阅读Mark Seemann 的书“.NET 中的依赖注入”并观看他关于约定的演讲。

答案

  1. 什么时候需要调用 InitializeKernel() 函数?当应用程序加载或表单加载时
  2. 我不熟悉ninject,所以我只是不明白这行代码的含义是什么.Configure((b, c) => b.InTransientScope().Named(c.Name)))
    • 每次注入依赖时,都会创建新实例
    • 依赖项可以通过它们的类名来引用
  3. 什么c.Name会返回?
    • 班级名称
  4. 我发现没有配置文件条目。ninject 不需要像 unity DI 这样的配置文件条目?
    • Ninject 仅支持流式配置
  5. 你声明了两个具有相同名称的方法,称为InitializeKernel()第二个InitializeKernel()是为了什么?
    • 只有一个方法声明InitializeKernel()
  6. 最后告诉我有没有可供ninject学习DI和ninject代码使用的pdf
于 2013-01-10T14:46:23.283 回答
1

首先,Seemann 有一本非常好的书“.NET 中的依赖注入”

许多 DI 容器的基准。

DI 的主要思想是消费者不能创建它所消费的服务的实例。
并且每个服务都应该以最抽象的方式呈现给客户端:接口/基类(在您的情况下是那个特殊功能)。

然后我必须为该公司创建另一个类库

这是不可避免的。如何引用这个新 API 并不重要。客户端代码不应该知道实现细节。

于 2013-01-10T13:18:40.187 回答