一、为什么要使用Ninject?

很多其它类型的IOC容器过于依赖配置文件,老是配置,总感觉有点不爽,而且要使用assembly-qualified名称(也就是类型的全名)来进行定义,稍不注意就会因为打错字而令整个程序崩掉。Ninject是一个快如闪电、超轻量级的基于.Net平台的IOC容器,主要用来解决程序中模块的耦合问题,它的目的在于做到最少配置。因此如果你不喜欢配置,不喜欢重量级IOC框架,那么就用小苹果Ninject吧!

二、Ninject的使用

首先你必须获取Ninject,其官网下载地址:http://www.ninject.org,你也可以通过VS中的NuGet来加载Nniject,不论是哪种方式,最终的目的就是将 Ninject.dll 这个程序集引用到你的项目中。这样在你的项目中,如果想使用Ninject,只需添加其命名空间引用即可~

using Ninject;

1、Ninject入门

我们先定义一个记录日志的接口

public interface ILogger
{
    void Write(string message);
}

然后用文件记录日志方式和数据库记录日志方式分别实现这个接口,不过这里只是演示而已,所以并没有真正去实现这两个类,你懂的~

public class FileLogger : ILogger
{
    public void Write(string message)
    {
        Console.WriteLine(String.Format("文件记录日志:{0}", message));
    }
}

public class DBLogger : ILogger
{
    public void Write(string message)
    {
        Console.WriteLine(String.Format("数据库记录日志:{0}", message));
    }
}

在Ninject中,我们可以通过重写Ninject.Modules.NinjectModule类的方法Load()而实现依赖注入,注意这里用的是代码的形式!

public class MyModule : Ninject.Modules.NinjectModule
{
    public override void Load()
    {
        Bind<ILogger>().To<FileLogger>();
        Bind<ILogger>().To<DBLogger>();
    }
}

具体调用方法:

private static IKernel kernel = new StandardKernel(new MyModule());
static void Main(string[] args)
{
    ILogger logger = kernel.Get<ILogger>();//获取的是FileLogger
    logger.Write(" Hello Ninject!");
    Console.Read();
}

没错,用Ninject进行依赖注入就是这么爽歪歪~

2、Ninject常用方法属性说明

这里我们使用构造函数注入一个栗子:

首先新建一个测试接口ITester与其实现类NinjectTester ,显然NinjectTester依赖于ILogger

interface ITester
{
    void Test();
}

class NinjectTester:ITester
{
    public string _Message{set;get;}

private ILogger _logger; public NinjectTester(ILogger logger) { _logger = logger; } public void Test() { _logger.Write("Hello Ninject!"); } }

下面就看看用Ninject的方式实现依赖注入的过程中用到的一些东东~

(1)Bind<T1>().To<T2>()

其实就是接口IKernel的方法,把某个类绑定到某个接口,T1代表的就是接口或者抽象类,而T2代表的就是其实现类

例如:

IKernel ninjectKernel = new StandardKernel();
ninjectKernel.Bind<ILogger>().To<FileLogger>();

(2)Get<ISomeInterface>()

其实就是得到某个接口的实例,例如下面的栗子就是得到ILogger的实例FileLogger:

ILogger myLogger= ninjectKernel.Get<ILogger>();

(3)Bind<T1>() .To<T2>(). WithPropertyValue("SomeProprity", value);

其实就是在绑定接口的实例时,同时给实例NinjectTester的属性赋值,例如:

ninjectKernel.Bind<ITester>().To<NinjectTester>().WithPropertyValue("_Message", "这是一个属性值注入");

(4)ninjectKernel.Bind<T1>().To<T2>(). WithConstructorArgument("someParam", value);

其实就是说我们可以为实例的构造方法所用的参数赋值,例如:

public class DefalutDiscountHelper : IDiscountHelper
    {
        private decimal discountRate;
        public decimal DiscountSize { get; set; }
        public DefalutDiscountHelper(decimal discountParam)
        {
            discountRate = discountParam;
        }

        public decimal ApplyDiscount(decimal totalParam)
        {
            return (totalParam - (discountRate / 100M * totalParam));
        }
    }
ninjectKernel.Bind<IDiscountHelper>().To<DefalutDiscountHelper>().WithConstructorArgument("discountParam", 50M);

(5)Bind<T1>().ToConstant()

这个方法的意思是绑定到某个已经存在的常量,例如:

StudentRepository sr = new StudentRepository();
ninjectKernel.Bind<IStudentRepository>().ToConstant(sr);

(6)Bind<T1>().ToSelf()

这个方法意思是绑定到自身,但是这个绑定的对象只能是具体类,不能是抽象类。为什么要自身绑定呢?其实也就是为了能够利用Ninject解析对象本身而已。例如:

ninjectKernel.Bind<StudentRepository>().ToSelf();
StudentRepository sr = ninjectKernel.Get<StudentRepository>();

(7)Bind<T1>().To<T2>().WhenInjectedInto<instance>()

这个方法是条件绑定,就是说只有当注入的对象是某个对象的实例时才会将绑定的接口进行实例化

ninjectKernel.Bind<IValueCalculater>().To<IterativeValueCalculatgor>().WhenInjectedInto<LimitShoppingCart>();

(8)Bind<T1>().To<T2>().InTransientScope()或者Bind<T1>().To<T2>().InSingletonScope()

 这个方法是为绑定的对象指明生命周期其实

ninjectKernel.Bind<IStudentRepository>().To<StudentRepository>().InTransientScope();
//每次调用创建新实例
ninjectKernel.Bind
<IStudentRepository>().To<StudentRepository>().InSingletonScope();
//每次调用是同一个实例

(9)Load()方法

 这里的Load()方法其实是抽象类Ninject.Modules.NinjectModule的一个抽象方法,通过重写Load()方法可以对相关接口和类进行集中绑定,例如:

public class MyModule : Ninject.Modules.NinjectModule
{
    public override void Load()
    {
        Bind<ILogger>().To<FileLogger>();
        Bind<ITester>().To<NinjectTester>();
    }
}

这是通过Load()方法绑定之后的完整代码:

private static IKernel kernel = new StandardKernel(new MyModule());
static void Main(string[] args)
{
    ITester tester = kernel.Get<ITester>(); // 因为是链式解析,因此只解析ITester即可,其它依赖的东东都会顺带解析  
tester.Test(); Console.Read(); }

(10)Inject属性

Inject中,我们可以通过在构造函数、属性和字段上加 Inject特性指定注入的属性、方法和字段等,例如下面的栗子,MessageDB有两个构造函数:intobject类型的。现在我们已经为int型的指定了Inject特性,因此在注入的时候选择的就是int型的构造函数;如果没有在构造函数上指定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 "从数据中读取消息号!";
        }
    }

 3、Ninject能使用配置文件吗?

答案是肯定的,要不怎么说Ninject是可扩展的呢,必须可以,但是如果这样的话,你就没必要用Ninject了,因为这样又回到了繁琐的配置上面,还不如用其他的IOC容器来得方便,这里用的是Ninject的XML扩展,你可以通过下面的地址https://github.com/ninject/ninject.extensions.xml下载扩展组件,主要也就是Ninject.Extensions.Xml这个东东起的作用,这里不想详说,给个栗子了结:

(1)配置文件

<?xml version="1.0" encoding="utf-8" ?>
<module name="ServiceModule">
  <bind name="Txtlog" service="LogService.ILogService,LogService" to="LogService.Impl.TxtLogService,LogService"/>
  <!--<bind name="Dblog" service="LogService.ILogService,LogService" to="LogService.Impl.DbLogService,LogService"/>-->
  <bind name="Sword" service="NinjectApp.Weapon.IWeapon,NinjectApp" to="NinjectApp.Weapon.Sword,NinjectApp"/>
  <bind name="FootSoldier" service="NinjectApp.Warrior.IWarrior,NinjectApp" to="NinjectApp.Warrior.FootSoldier,NinjectApp"/>
</module>
View Code

(2)利用扩展加载服务

using System.Collections.Generic;
using System.Xml.Linq;
using Ninject;
using Ninject.Extensions.Xml;
using Ninject.Extensions.Xml.Handlers;

namespace NinjectApp
{
    public class XmlModuleContext
    {
        protected readonly IKernel kernel;
        protected readonly IDictionary<string, IXmlElementHandler> elementHandlers;

        public XmlModuleContext()
        {
            kernel = new StandardKernel();
            elementHandlers = new Dictionary<string, IXmlElementHandler> { { "bind", new BindElementHandler(kernel) } };
        }
    }

    public class XmlServiceModule : XmlModuleContext
    {
        private static readonly XmlServiceModule instance = new XmlServiceModule();

        protected readonly XmlModule module = null;

        public XmlServiceModule()
        {
            var document = XDocument.Load("Config/NinjectServiceModule.config");
            module = new XmlModule(document.Element("module"), elementHandlers);
            module.OnLoad(kernel);
        }

        public static IKernel GetKernel()
        {
            return instance.kernel;
        }
    }
}
View Code

相关文章: