关于使用C#实现依赖注入

时间:2013-01-10 13:03:39

标签: c# dependency-injection

我从未在应用程序中使用依赖注入。我通过几篇关于依赖注入的文章,发现这个概念很有意思但很难在现实生活中实现。现在我想在我的win form apps中实现Dependency Injection。

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

例如我有一个表格,其中有4个按钮。就像那些按钮是“Ship with UPS WorldShip”,另一个按钮叫做“Ship with UPS WebAPI”,另一个按钮名为“Ship with FedEX Desktop Apps”,另一个按钮名为“Ship with Fedex WebAPI”。

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

当用户点击FedEX WinApps按钮时,会在文件夹中生成一个平面文件。 当用户点击FedEX WebAPI按钮,然后请求进入FedEx网站。

所以当用户点击任何按钮时我现在所做的就是我在dll中调用一个特定的函数来完成任务。

我的一切工作正常,但问题是我们公司开始与另一家新的运输公司合作,然后我必须为该公司创建另一个类库。

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

我的第二阶段问题

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

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

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

3)c.Name会返回什么?

4)我发现没有配置文件条目。 ninject不需要像Unity DI那样配置文件条目吗?

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

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

感谢

我的第三阶段问题

非常抱歉,右边的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的相关信息并加载&amp;实例化所有来自那里的所有dll,它会更好。所以我在寻找你的建议。感谢

2 个答案:

答案 0 :(得分:2)

似乎你要Configuration by Convention。这意味着您可以识别应该共享公共配置的组件组,然后在read more about it

中在单个语句中指定该组态

实际上,这意味着您将所有具有选定功能“交付”的库部署到项目中的“特殊”位置,并从“特殊”界面继承所有实现。最后,让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内核构建配置(在本例中为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; 
} 

如何解决依赖关系

Composition root of application按名称解析递送服务

// 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!
}

所有可用资源here

摘要

按惯例进行配置是许多项目中已采用的非常有用的方法。不过,我建议您阅读Mark Seemann book "Dependency Injection in .NET"并观看他的talk about conventions

答案

  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. 最后告诉我是否有任何pdf可供ninject学习DI和ninject代码使用

答案 1 :(得分:1)

首先是一本非常好的书"Dependency Injection in .NET" by Seemann

here is许多DI容器的基准。

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

  

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

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