Ninject Injection Patterns

来源:互联网 发布:阿里云中央仓库 编辑:程序博客网 时间:2024/05/20 03:44

Ninject Injection Patterns

1.依赖注入模式

Ninject 创造性的支持三种类型的注入模式,每种类型都有优缺点。我们需要根据不同情境来决定使用哪种注入模式。

Constructor Injection

主要的依赖注入模式是 Constructor Injection.当激活一个类型的实例时,Ninject将按照如下给出的顺序选择一个这个类型的构造函数:

1.如果一个构造函数拥有一个[Inject]特性,那么它将被使用(如果你对多造函数使用[Inject]特性,那么在运行时进行检测的过程中抛出 NotSupportedException 的异常)。
2.如果没有构造函数包含[Inject]特性,Ninject 将选择一个可以确定最多参数的构造方法。
3.如果没有构造函数被定义,Ninject 将选择默认的无参构造函数。

class Samurai {    readonly IWeapon weapon;    public Samurai(IWeapon weapon)    {        if(weapon == null)            throw new ArgumentNullException("weapon");        this.weapon = weapon;    }    public void Attack(string target)    {        this.weapon.Hit(target);    }}

上面的这种实现方式具有如下优点:
1.在一个地方可以看到全部的依赖关系
2.避免了不必要混淆的产生
3.所有的验证可以在同一个地方实现
4.你可以使用编译器提供的 readyonly 关键字来确定字段不会被改变
5.你的代码将不用频繁的去访问DI容器
6.如果你在编写测试代码,或者是在DI容器外部使用一个类型,编译器将清楚的给出这个类的依赖项

我们还应该注意到[Inject]特性可以完全不被使用。也就是说你的大部分代码可以不关注Ninject和引用Ninject的命名空间以及程序集。如果无法访问一个类但却要注入依赖关系到这个类,这将是一件危险的事情(我们也可以告诉Ninject通过添加一些自定义的特性比如一些除了[Inject]外的其他特性,通过设置Ninject属性从而采用这个特性。)。

Initialization methods

如果Constructor Injection 不能满足你的需求,Ninject提供了两种方法,用于在容器构造完成后提供依赖性。虽然表面上看起来很不一样,但是它们的机制和语法基本相同:1.在构造开始以后,被[Inject]亦或是其他设定的特性标记过的方法和属性,将被赋值依赖项所设定的实例。2.调用的顺序并不确定,没有方法告诉Ninject以何种顺序来注入这些值,然而你可以通过实现IInitializable 和 IStartable 接口请求在所有的注入动作完成后给予通知。与Constructor Injection 相比,它的主要缺点是:1.你不能通过使用 readyonly 关键字来依赖编译器保证初始化时的正确性。2.分析这些有可能给 weapon 赋值的地方要比追溯到单一的构造函数要复杂的多。3.你将不再能够一眼看出类型的依赖性4.它要求[Inject]的特性声明在用的到的地方必须可见,这将把你的代码绑定到一个特殊的容器上。5.为了保护类中的不变量,我们有必要考虑在外部的任何人任何时候任何顺序调用初始化方法时,执行验证逻辑。

Setter Method Injection

如下对Samurai类以Setter Method Injection 的方式进行了重写,一个方法将在创建实例后被调用,它必须用[Inject]特性进行标记。
class Samurai{    IWeapon weapon;    [Inject]    public void Arm(IWeapon weapon)    {        this.weapon = weapon;    }    public void Attack(string target)     {        this.weapon.Hit(target);    }}

我们可以在类的继承层级上标记多个方法,每一个被标记的方法将在对象组成图上被调用,但是没有办法确定它们被调用的先后顺序。

Property Setter Injection

如下将 samurai 类以Property Setter Injection 的方式进行重写,被依赖注入的属性需要添加[Inject]特性:

class Samurai {        [Inject]    public IWeapon Weapon { private get; set; }    public void Attack(string target)     {        this.Weapon.Hit(target);    }}

Setter Method Injection 是 Property Setter Injection 的一个特例,这是没有明确的指出 set_PropertyName 的方法名,因此具有其相同的缺点。虽然表面上看起来它比上面提到的Constructor Injection 更加整洁,但是它具有更多缺点,在考虑使用这种方式时要更加的慎重。

另外,你的类接口还存在如下缺点:

1.如上所用的一个只写属性,被认为是一种糟糕的实践
2.使 getter 访问器可见将通过公开接口暴露外部依赖关系管理,这将是一个坏主意

Injecting Fields

Fields Injection 是一个差强人意的实践,在新版的Ninject中删除了这种注入方式。