http://www.bbsmvc.com/archiver/csharp/thread-831-1.html

本来想使用一下Ninject的,然后搜索了很久,都没找到比较详细的关于Ninject的使用方法等内容.于是乎干脆自己来写几篇介绍Ninject的内容.
1.      依赖注入和IOC
依赖注入和IOC的概念,可以点击这里看之前的文章.在这里就不多介绍了.
2.      环境准备
Ø  开发环境:WIN7 + VS2010 SP1
Ø  Ninject:本节内容以Ninject2.2.0.0-release-net-4.0为基础进行介绍。可以点击这里打开Ninject的官网进行下载。需要说明的是,CodePlex上虽然也有Ninject项目,但其基本没怎么更新。所以就不要从那里下载了。直接到Ninject其官方网站下载吧。
3.简单的例子
Ø  需求描述:
系统有任务消息,每个任务消息都有消息号,消息号的产生可以是以配置文件中的基数为基础产生,也可以是根据数据库中的某个字段产生。
Ø  步骤:
1).定义一个消息接口:

public interface IMessage
   {
       /// <summary>
       /// 取得消息号
       /// </summary>
       /// <returns></returns>
       string GetMsgNumber();
   }

2).从配置文件中获取消息号,实现消息接口。代码如下:

public class MessageFile : IMessage
   {
       public string GetMsgNumber()
       {
           return "从文件中获取消息号!";
       }
   }

3).从数据库中获取消息号,实现消息接口。代码如下:

public class MessageDB : IMessage
   {
       public string GetMsgNumber()
       {
           return "从数据中读取消息号";
       }
   }

4).下面就是准备在我们的应用中注册的接口和接口实现了。代码如下:

using Ninject.Modules;
public class MessageModule : NinjectModule
   {
       public override void Load()
       {
           //绑定接口并指定接口的实现。
           Bind<IMessage>().To<MessageDB>();
       }
   }

通过代码我们可以看到,我们只需要继承自NinjectModule并重载其Load()方法,在Load()方法中进行绑定接口并指定其具体实现即可。
5).接着,就是具体的使用了,代码如下:

using Ninject;
static void Main(string[] args)
       {
           using (var kernal = new StandardKernel(new MessageModule()))
           {
               var msg = kernal.Get<IMessage>();
               var msgNo = msg.GetMsgNumber();
               Console.WriteLine(msgNo);
               Console.Read();
           }
       }

运行代码(注意:在运行代码之前,请将项目的Framework选择中4.0版本,否则会“未能解析引用的程序集“Ninject”,因为它对不在当前目标框架“.NETFramework,Version=v4.0,Profile=Client”中的“System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”具有依赖关系“异常出现),最后我们可以看到,控制台打出的消息是:

从数据中读取消息号!
 
在代码中,我们通过Kernal的Get方法来取得相应的类型实例,在这整个代码过程中,我们只是在Module中绑定了接口和实现,然后在其他地方都是通过接口类型来实现代码的。如何需要换成从配置文件中获取消息号,则只需要修改自定义的Module中的代码即可。毫无疑问,在程序的类型依赖和耦合方面都有很多优点。

4.接下来,介绍使用Ninject进行依赖注入的几种方式。
Ø  构造函数注入
首先,定义使用依赖接口初始化的类, 具体如下:

public class MessageCfg
   {
       private readonly IMessage msg;
       /// <summary>
       /// 通过接口构造
       /// </summary>
       /// <param name="msg"></param>
       public MessageCfg(IMessage msg)
       {
           this.msg = msg;
       }
 
       public string GetMsgNumber()
       {
           return this.msg.GetMsgNumber();
       }
   }

然后,我们的代码就可以这样写了:

using (var kernal = new StandardKernel(new MessageModule()))
           {
               var msg = kernal.Get<IMessage>();
               var msgcfg = new MessageCfg(msg);//构造函数注入
               Console.WriteLine(msgcfg.GetMsgNumber());
               Console.Read();
           }

这里,我们可以初始化MessageCfg的时候,只需要使用kernal.Get<IMessage>()获取的类型即可,而不用关心其具体是什么。
Ø  属性注入
首先定义使用属性注入的类,具体如下:

public class MessageCfg
   {
      //定义接口属性
       public IMessage Msg { get; set; }
       public MessageCfg() { }
       public string GetMsgNumber()
       {
           return this.Msg.GetMsgNumber();
       }
   }

具体使用代码如下:

using (var kernal = new StandardKernel(new MessageModule()))
           {
               //属性注入
               var msgcfg = new MessageCfg() { Msg = kernal.Get<IMessage>() };
               Console.WriteLine(msgcfg.GetMsgNumber());
               Console.Read();
           }

其他几种注入都大同小异,使用方式差不多。
最后,我们可以看到使用Ninject的基本步骤很简单。只需要定义接口à实现接口à继承NinjectModule在其Load()方法中指定相应的绑定接口和接口实现à通过自己的Module的来初始化Kernalà通过Get方法来获得相应的实现。

Ninject中提供多种接口和实现类的绑定的方式供我们选择,同时还可以设置相关的绑定项以及对象的作用域等。具体如下:(其中使用到的类和代码重用上一节的“Ninject 2.x细说---1.基本使用”中的定义)
1.        绑定:
Ninject中提供好几种绑定接口实现的方法,具体如下:

Ø To:绑定到接口的具体实现。

Ø ToConstant:绑定到某个常量值。
Ø ToMethod:绑定到方法。
Ø ToProvider:绑定到某个自定义的对象创建提供程序。
Ø ToSelf:自绑定。
代码如下:
1)        自绑定
Ninject可以使用ToSelf()方法,将自己绑定自己,这里必须是一个具体的类。

Bind<MessageCfg>().ToSelf();

2)        绑定到方法:

Bind<IMessage>().ToMethod(context => new MessageDB());

3)        绑定到具体的类型

Bind<IMessage>().ToConstant(new MessageDB());

4)        绑定到指定的服务提供程序

以及Bind<IMessage>().ToProvider(实现IProvider接口的服务提供程序);

2.        指定相关绑定信息:
Ninject中,可以在绑定的时候指定一些附加信息,以便更加明确构造函数或者是给某些属性赋值或者在绑定时回调方法。如下面的代码中:Bind<IMessage>().To<MessageDB>().WithConstructorArgument("msg", 1);
我们在绑定的同时指定了构造函数的参数以及值。
此外,还可以设置的指定信息分别有:

Ø WithConstructorArgument:指定构造函数中相关的参数,还有回调方法的重载。
Ø WithMetadata:指定相关元数据信息。
Ø WithParameter:指定相关的自定义参数。这个方法也实现构造函数参数值指定,与WithConstructorArgument类似,如:Bind<IMessage>().To<MessageDB>().WithConstructorArgument("msg", 1);同样可以写成:Bind<IMessage>().To<MessageDB>().WithParameter(newConstructorArgument("msg", 1));
Ø WithPropertyValue:指定相关的属性值,还有回调方法的重载。

3.        条件绑定:
Ninject中还可以指定相关的绑定的条件,只有条件满足的情况的下,才将相关的接口实现绑定到相关的接口上。如:

Bind<IMessage>().To<MessageDB>().WhenInjectedInto<MessageCfg>();

上面的代码,由于MessageCfg依赖与IMessage接口,所以其意思是在MessageCfg类中依赖的IMessage接口与MessageDB类绑定。
类似的还有When()如:

Bind<IMessage>().To<MessageDB>().When(cxt => cxt.Service.Name.StartsWith("Msg"));

其他的条件还有WhenClassHas、WhenParentNamed、WhenTargetHas等条件绑定。

 

4.        设置注入项
在Ninject中可以通过NinjectSettings类来指定注入项。如:

////设置注入项
var settings = new NinjectSettings() { AllowNullInjection = true };
using (var kernal = new StandardKernel(settings, new MessageModule()))
{
var msgcfg = kernal.Get<MessageCfg>();
}

其中,可以设置的项有:
ActivationCacheDisabled、AllowNullInjection、CachePruningInterval、ExtensionSearchPattern、InjectAttribute、InjectNonPublic等等。大概对应的就是设置缓存是否启用、是否允许空注入、缓存周期、扩展查找位置、必须被注入的属性、是否必须注入非公开成员等等。(BTW:Ninject中摘要说明少了Get,还发现好几个地方都是这样呢)。

 

5.        Inject特性
在Inject中,我们构造函数、属性和字段上加 [Inject]特性指示,以便指定注入的属性、方法和字段等。[Inject]特性定义具体如下:

[AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple =false, Inherited = true)]
   public class InjectAttribute : Attribute
   {
       public InjectAttribute();
   }

例如使用[Inject]指定构造函数,如果某个类存在多个构造函数,那么我们就可以在某个构造函数上使用[Inject]来指定从此处注入,具体代码如下:

public class MessageDB : IMessage
   {
       public MessageDB() { }
 
 
       public MessageDB(object msg)
       {
           Console.WriteLine("使用了object 参数构造:{0}", msg);
       }
 
       [Inject]
       public MessageDB(int msg)
       {
           Console.WriteLine("使用了int 参数构造:{0}", msg);
       }
       public string GetMsgNumber()
       {
           return "从数据中读取消息号!";
       }
   }

相应的MessageModule进行修改,具体如下:

public class MessageModule : NinjectModule
   {
       public override void Load()
       {
           //绑定接口并指定接口的实现。
           Bind<IMessage>().To<MessageDB>().WithConstructorArgument("msg", 1);
       }
}

具体使用如下:

using (var kernal = new StandardKernel(new MessageModule()))
           {
               //属性注入
               var msgcfg = new MessageCfg() { Msg = kernal.Get<IMessage>() };
               Console.WriteLine(msgcfg.GetMsgNumber());
               Console.Read();
           }

其中MessageCfg类的定义见前一节介绍的内容。通过上面的代码,我们可以看到,MessageDB分别由int和object类型的构造函数,如果没有在构造函数上指定[Inject],经过测试发现它默认就是选择第一个构造函数,如果参数类型不匹配就直接抛出异常。
6.        对象作用域:

Transient .InTransientScope() 每次调用创建新实例。
Singleton .InSingletonScope() 单例,仅创建一个实例。
Thread .InThreadScope() 每一个线程创建一个实例。
Request .InRequestScope() 每当Web请求发起时创建一个实例,结束请求时释放实例
InScope InScope(Func) 对象尽量保持到回调委托返回

上表来自“靠近太阳”的博文,后增加了InScope 。如使用InThreadScope()具体例子如下:

public class MessageModule : NinjectModule
   {
       public override void Load()
       {
           //绑定接口并指定接口的实现。
           Bind<IMessage>().To<MessageDB>().InThreadScope().WithParameter(new ConstructorArgument("msg", 1));
 
       }
   }

使用代码如下:

using (var kernal = new StandardKernel(new MessageModule()))
           {
               //属性注入
               var th1 = new Thread(new ThreadStart(() =>
               {
                   var msgcfg = new MessageCfg() { Msg = kernal.Get<IMessage>() };
                   Console.WriteLine(msgcfg.GetMsgNumber());
               }));
               var th2 = new Thread(new ThreadStart(() =>
               {
                   var msgcfg = new MessageCfg() { Msg = kernal.Get<IMessage>() };
                   Console.WriteLine(msgcfg.GetMsgNumber());
               }));
               var th3 = new Thread(new ThreadStart(() =>
               {
                   var msgcfg = new MessageCfg() { Msg = kernal.Get<IMessage>() };
                   Console.WriteLine(msgcfg.GetMsgNumber());
               }));
 
               th1.Start();
               th2.Start();
               th3.Start();
               Console.Read();
           }
       }

在上面的代码中,我们指定了对象在InThreadScope,在使用的代码中分别创建了3个线程来进行模拟,最终每个线程都是创建了一个对象。

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://www.cnblogs.com/xray2005/

依赖注入和IOC的更多相关文章

  1. Atitit js中的依赖注入di ioc的实现

    Atitit js中的依赖注入di ioc的实现 全类名(FQCN)为标识符1 混合请求模式1 使用类内  builder  即可..2 Service locator method走ok拦2 Jav ...

  2. spring 依赖注入(IOC DI)

    依赖注入(IOC DI) 依赖注入的两种方式: 1. set注入 Spring要求使用set注入方式的时候,Bean需要提供一个无参数的构造方法.并提供一个属性的setter方法.例如: packag ...

  3. 依赖注入(IOC)二

    依赖注入(IOC)二 上一章我们讲了构造注入与设值注入,这一篇我们主要讲接口注入与特性注入. 接口注入 接口注入是将抽象类型的入口以方法定义在一个接口中,如果客户类型需要获得这个方法,就需要以实现这个 ...

  4. 依赖注入(IOC)

    依赖注入(IOC) 背景介绍 在设计模式中,尤其是结构型模式很多时候解决的就是对象间的依赖关系,变依赖具体为依赖抽象.平时开发中如果发现客户程序依赖某个或某类对象,我们常常会对他们进行一次抽象,形成抽 ...

  5. [ASP.NET Core 3框架揭秘] 依赖注入:IoC模式

    原文:[ASP.NET Core 3框架揭秘] 依赖注入:IoC模式 正如我们在<依赖注入:控制反转>提到过的,很多人将IoC理解为一种“面向对象的设计模式”,实际上IoC不仅与面向对象没 ...

  6. C#中的依赖注入和IoC容器

    在本文中,我们将通过用C#重构一个非常简单的代码示例来解释依赖注入和IoC容器. 简介: 依赖注入和IoC乍一看可能相当复杂,但它们非常容易学习和理解. 在本文中,我们将通过在C#中重构一个非常简单的 ...

  7. 在 MVC 控制器中使用 构造函数时行依赖注入 (IoC)

    在 Controller 中使用 构造函数进行依赖注入 (IoC) 1. Controller 代码: ICard card; ICardCategory cardCategory; public C ...

  8. 【转】理解依赖注入(IOC)和学习Unity

    IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection).作用:将各层的对象以松耦合的方式组织在一起,解耦,各 ...

  9. 理解PHP 依赖注入|Laravel IoC容器

    看Laravel的IoC容器文档只是介绍实例,但是没有说原理,之前用MVC框架都没有在意这个概念,无意中在phalcon的文档中看到这个详细的介绍,感觉豁然开朗,复制粘贴过来,主要是好久没有写东西了, ...

随机推荐

  1. 使用Mockito进行单元测试【2】—— stub 和 高级特性[转]

    一篇中介绍了Mockito的基本信息,现在接着介绍Mockito强大的stub功能 2. Mockito使用实例 5. 对连续的调用进行不同的返回 (iterator-style stubbing) ...

  2. Sql Server 2008R2版本中有关外键Foreign的使用

    原文:Sql Server 2008R2版本中有关外键Foreign的使用 1. 在数据库设计的过程中往往会想让2张表进行关联而使用到Foreign从而加强2张表之间的约束(如图) 以前有个问题一直没 ...

  3. sql server中的索引详情

    什么是索引 拿汉语字典的目录页(索引)打比方:正如汉语字典中的汉字按页存放一样,SQL Server中的数据记录也是按页存放的,每页容量一般为4K .为了加快查找的速度,汉语字(词)典一般都有按拼音. ...

  4. Android Fragment与Activity之间的数据交换(Fragment从Activity获取数据)

    Fragment与Activity之间的数据交换,通常含有3: 一.Fragment从Activity获取数据(仅本文介绍了一个第一): 两.Activity从Fragment获取数据: 三.Frag ...

  5. SQL Server AlwaysON 同步模式的疑似陷阱

    原文:SQL Server AlwaysON 同步模式的疑似陷阱 SQL Server 2012 推出的最重要的功能之一Alwayson,是一个集之前Cluster和Mirror于一体的新功能,即解决 ...

  6. 【高德地图API】从零开始学高德JS API(四)搜索服务——POI搜索|自动完成|输入提示|行政区域|交叉路口|自有数据检索

    原文:[高德地图API]从零开始学高德JS API(四)搜索服务——POI搜索|自动完成|输入提示|行政区域|交叉路口|自有数据检索 摘要:地图服务,大家能想到哪些?POI搜素,输入提示,地址解析,公 ...

  7. 分布式基础学习(2)分布式计算系统(Map/Reduce)

    二. 分布式计算(Map/Reduce) 分 布式式计算,同样是一个宽泛的概念,在这里,它狭义的指代,按Google Map/Reduce框架所设计的分布式框架.在Hadoop中,分布式文件 系统,很 ...

  8. C# 调用Webservice并传递序列化对象

    原文:C# 调用Webservice并传递序列化对象 C#动态调用WebService注意要点 1.动态调用的url后面注意一定要加上?WSDL   例如:string _url = "ht ...

  9. 接口自动化测试:参数化封装(excel文件读取)

    log4j.properties文件配置 log4j.rootLogger = DEBUG,stdout,F log4j.appender.stdout = org.apache.log4j.Cons ...

  10. 拥抱HTTP2.0时代 - HTTP2.0实现服务器端推送Push功能

    在当今的移动互联开发趋势中,nghttp2是一个很值得大家去关注的一个开源项目. 我们在nghttpx模块中实现了HTTP/2服务器推送功能,并且在我们的nghttp2.org网站中启用了该推送功能. ...