Ninject简介(转)

1.为什么要用Ninject?

Ninject是一个IOC容器用来解决程序中组件的耦合问题,它的目的在于做到最少配置。其他的的IOC工具过于依赖配置文件,需要使用assembly-qualified名称来进行定义,庸长且复杂常常因为打错字而破坏程序。这些是他的优点,也是为什么要选择它。Ninject同时不能进行热插拔。

2.Ninject做些什么?

其实Ninject做的事情很简单,说白了就是为我们选择一个想要的类来处理事务。来看下面的简单的例子。

    public class Product
    {
        public int ProductID { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
        public string Category { get; set; }
    }

    public interface IValueCalculater
    {
        decimal ValueProducts(params Product[] products);
    }

    public class LinqValueCalculator : IValueCalculater
    {
        public decimal ValueProducts(params Product[] products)
        {
            return products.Sum(p => p.Price);
        }
    }

我们定义了一个实体类,一个接口,一个实现接口的类,这个类完成的功能是计算总价。

    public class ShoppingCart
    {
        protected IValueCalculater calculator;
        protected Product[] products;

        public ShoppingCart(IValueCalculater calcuParam)
        {
            this.calculator = calcuParam;
            products = new[]{
                                new Product(){Name="Kayak" , Price=275M},
                                new Product(){Name="Lifejacket" , Price=48.95M},
                                new Product(){Name="Scooceer ball" , Price=19.5M},
                                new Product(){Name="Stadium" , Price=79550M}
                            };
        }

        public virtual decimal CalculatStockValue()
        {
            decimal totalPrice = calculator.ValueProducts(products);
            return totalPrice;
        }
    }

ShopingCart类的构造函数使用接口IValueCalculater实现作为一个准备DI的参数。CalculatStockValue方法创建一个Product对象数组,然后调用IValueCalculater接口中的ValueProducts来获得总价。这里可以看到ShoppingCart类中只出现了接口IValueCalculater,却没有出现这个接口的实现类LinqValueCalculator,说的直白点就是ShoppingCart中计算的总价是一个影藏的类实现的,我们可以修改这个影藏的类达到修改总价的目的,而不需要修改ShoppingCart类中的代码。好的,Ninject做的工作就是和上面的类似,是的,它只能完成这么个工作,不过会有很多的变化,最终目的只有一个,就是决定到当前到底要使用哪一个类似LinqValueCalculator着那个的实现类。

3.Ninject的使用

关于如何下载安装Ninject这里不再说了,网上有很多的资源。这里只说几个简单的例子。

            IKernel ninjectKernel = new StandardKernel();
            ninjectKernel.Bind<IValueCalculater>().To<LinqValueCalculator>();

上面的代码将想使用的类型和他的接口进行绑定,高祖Ninject,当接收到一个实现IValueCalculater的请求的时候,创建病返回LinqValueCalculator这个类,上面的两个关键字Bind,To可以帮助我们理解他的意思。

IValueCalculater calcImpl = ninjectKernel.Get<IValueCalculater>();
ShoppingCart cart = new ShoppingCart(calcImpl);

当我们调用上面两句的时候就会去计算总价。

下面我们看看他的变形。

1.依赖性链

当使用ninjectKernel.Get创建一个类型的时候会检查这个类型与其他类型之间的耦合,如果有额外的依赖性,Ninject会解析这些依赖性,并创建所需要的所有的类的类型。下面我们在LinqValueCalculator中再次依赖其他的类型。

    public interface IDiscountHelper
    {
        decimal ApplyDiscount(decimal totalParam);
    }

    public class DefalutDiscountHelper : IDiscountHelper
    {
        private decimal discountRate;

        public DefalutDiscountHelper(decimal discountParam)
        {
            discountRate = discountParam;
        }

        public decimal ApplyDiscount(decimal totalParam)
        {
            return (totalParam - (discountRate / 100M * totalParam));
        }
    }

    public class LinqValueCalculator : IValueCalculater
    {
        IDiscountHelper discounter;

        public LinqValueCalculator(IDiscountHelper discountParam)
        {
            discounter = discountParam;
        }

        public decimal ValueProducts(params Product[] products)
        {
            return discounter.ApplyDiscount(products.Sum(p => p.Price));
        }
    }

和IValueCalculator所做的那样我们把IDiscountHelper和DefalutDiscountHelper 关联起来。

ninjectKernel.Bind<IDiscountHelper>().To<DefalutDiscountHelper>();IValueCalculater calcImpl = ninjectKernel.Get<IValueCalculater>();

当IValueCalculater被请求的时候,Ninject知道它要实例化的是LinqValueCalculator,然后进一步考察这个类,并发现他依赖一个可以解析的接口,Ninject会创建DefaultDiscountHelper的一个实例,并把它注入到LinqValueCalculator类的构造器中,一IValueCalculator作为返回结果,不管这个依赖性链有多长,多复杂,Ninject都会以这种方式检查它要实例化的每一个依赖性。

2.指定属性和参数值

修改DefalutDiscountHelper 类如下

    public class DefalutDiscountHelper : IDiscountHelper
    {
        private decimal discountRate;

        public decimal DiscountSize { get; set; }

        public decimal ApplyDiscount(decimal totalParam)
        {
            return (totalParam - (DiscountSize / 100M * totalParam));
        }
    }

在使用Ninject将具体类绑定到类型的时候,我已使用WithPropertyValue方法来设置DefalutDiscountHelper 类中的属性DiscountSize,方法如下

            ninjectKernel.Bind<IDiscountHelper>().To<DefalutDiscountHelper>()
                                                 .WithPropertyValue("DiscountSize", 50M);
IValueCalculater calcImpl = ninjectKernel.Get<IValueCalculater>();

3.指定构造函数的参数值

如果具体类中有带参数的构造函数可以使用WithConstructorArgument方法来指定这个参数,修改DefalutDiscountHelper如下

    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));
        }
    }

使用Ninject绑定如下:

            ninjectKernel.Bind<IDiscountHelper>().To<DefalutDiscountHelper>()
                                                  .WithConstructorArgument("discountParam", 50M);
IValueCalculater calcImpl = ninjectKernel.Get<IValueCalculater>();

4.上面我们都是绑定接口,其实只要是有继承关系的两个类之间也可以进行绑定,下面我们来看一个例子,我们先顶一个ShoppingCart类,然后定义一个LimitShoppingCart类来继承它,代码如下:

    public class ShoppingCart
    {
        protected IValueCalculater calculator;
        protected Product[] products;

        public ShoppingCart(IValueCalculater calcuParam)
        {
            this.calculator = calcuParam;
            products = new[]{
                                new Product(){Name="Kayak" , Price=275M},
                                new Product(){Name="Lifejacket" , Price=48.95M},
                                new Product(){Name="Scooceer ball" , Price=19.5M},
                                new Product(){Name="Stadium" , Price=79550M}
                            };
        }

        public virtual decimal CalculatStockValue()
        {
            decimal totalPrice = calculator.ValueProducts(products);
            return totalPrice;
        }
    }
    public class LimitShoppingCart : ShoppingCart
    {
        public decimal ItemLimit { get; set; }

        public LimitShoppingCart(IValueCalculater calcParm)
            : base(calcParm)
        { }

        public override decimal CalculatStockValue()
        {
            var filteredProducts = products.Where(e => e.Price < ItemLimit);
            return calculator.ValueProducts(filteredProducts.ToArray());
        }
    }

下面的代码将子类绑定到它的父类上,代码如下:

            ninjectKernel.Bind<ShoppingCart>().To<LimitShoppingCart>().WithPropertyValue("ItemLimit",200M);
            ShoppingCart cart = ninjectKernel.Get<LimitShoppingCart>();

5.使用条件绑定

可以使用Ninject绑定同一个接口的多个实现,或同一个类的多个派生类,并在不同条件下绑定不同的类。我们可以对当前绑定的具体类进行判断,最终绑定另外一个具体类,先来定义一个IValueCalculator的另外一个实现类,代码如下

        public decimal ValueProducts(params Product[] products)
        {
            decimal totalValue = 0;

            foreach (Product p in products)
            {
                totalValue += p.Price;
            }
            return totalValue;
        }

下面的代码将有选择的创建Ninject类。

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

这段代码的意思是当LimitShoppingCart这个类被绑定的时候才将IterativeValueCalculatgor绑定到它的接口中,我们可以将IterativeValueCalculatgor和LimitShoppingCart看做是一套具体的逻辑,是有具体关系的,例如这是同一次促销的产品,即他们是为同一此促销活动而新建的类,这就为我们的业务逻辑实现提供一个便利。

3.将Ninject用于ASP.NET MVC

这部分本人还没有用到过,是从书本中看到的,也是初次接触。DefaultControllerFactory类是创建控制器类实例的一个类。先看代码吧。

    public class NinjectControllerFactory : DefaultControllerFactory
    {
        private IKernel ninjectKernel;

        public NinjectControllerFactory()
        {
            ninjectKernel = new StandardKernel();
            AddBindings();
        }

        private void AddBindings()
        {
            ninjectKernel.Bind<IValueCalculater>().To<LinqValueCalculator>();
        }

        protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);
        }
    }

这个类创建了一个Ninject内核,用它对控制器类的请求进行服务,请求是通过GetControllerInstance方法实现的,它是在MVC框架在需要一个控制器对象时调用的。我们不需要明确的绑定控制器,可以依靠默认的自身绑定特性,因为控制器是从System.Web.Mvc.Controller派生来的具体类。

AddBinding方法允许我们队存储库和希望保持送耦合的组件添加Ninject绑定,也可以吧这个方法用于对需要额外的构造器参数或者属性的控制器进行绑定,说的明白点就是我们上面展示的那些需要自己绑定的类。

创建了这个类可以用MVC框架对它进行注册,在Global.asax类的Application_Start方法中来完成注册,代码如下

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
        }

现在我们使用NinjectControllerFactory来获得控制器的实例,而Ninject将自动第吧DI运用到控对象中。

希望这篇简单的介绍对你有用。

=============================================================

作者:Tyler Ning
出处:http://www.cnblogs.com/tylerdonet/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,可以通过以下邮箱地址[email protected]  联系我,非常感谢。
时间: 2024-07-30 16:41:12

Ninject简介(转)的相关文章

IOC框架之Ninject 简介

还是那几句话: 学无止境,精益求精 十年河东,十年河西,莫欺少年穷 学历代表你的过去,能力代表你的现在,学习代表你的将来 上篇博客介绍了依赖注入的三种方式:构造方法注入,属性注入,接口注入!详情请参考:学习 IOC 设计模式前必读:依赖注入的三种实现 本篇继续介绍IOC和DI的故事 今天将以一个具体的IOC框架来介绍,Ninject 框架: 1.Ninject简介 Ninject是基于.Net平台的依赖注入框架,它能够将应用程序分离成一个个高内聚.低耦合(loosely-coupled, hig

Ninject依赖注入——构造函数的注入

1.Ninject简介 Ninject是基于.Net平台的依赖注入框架,它能够将应用程序分离成一个个高内聚.低耦合(loosely-coupled, highly-cohesive)的模块,然后以一种灵活的方式组织起来.Ninject可以使代码变得更容易编写.重用.测试和修改. Ninject官方网址为:http://www.ninject.org/ . 2.项目引用Ninject 1>. Tools -> Libaary Package Manager -> Package Manag

依赖注入(DI)和Ninject,Ninject

我们所需要的是,在一个类内部,不通过创建对象的实例而能够获得某个实现了公开接口的对象的引用.这种“需要”,就称为DI(依赖注入,Dependency Injection),和所谓的IoC(控制反转,Inversion of Control )是一个意思. DI是一种通过接口实现松耦合的设计模式. 依赖注入(DI)和Ninject Ninject简介

记录.net 中的常见术语

--Entity Framework和NHibernate --EF和NH都是一种ORM技术.就是对象关系模型映射. --NHibernate和Entity Framework 4.0优劣势争论 --比较NHibernate和Entity Framework --LINQ --LINQ是一种查询语言 --30分钟LINQ教程 --Linq之旅:Linq入门详解(Linq to Objects) --Ninject --Ninject是一个快如闪电.超轻量级的基于.Net平台的依赖注入(IOC容器

Note3:大话Ninject

1.简介 Ninject(官网:http://www.ninject.org/)是一个快如闪电,超轻量级的基于的.Net平台的依赖注入框架.它能够帮助你把应用程序分离成一个个松耦合,高内聚的模块,然后用一种灵活的方式组装起来.通过使用Ninject配套你的软件架构,那么代码将会变得更加容易编写,重用性强,易于测试和修改. Ninject is a lightning-fast, ultra-lightweight dependency injector for .NET applications

Android网络通讯简介

网络通信应该包含三部分的内容:发送方.接收方.协议栈.发送方和接收方是参与通信的主体,协议栈是发送方和接收方进行通信的契约.按照服务类型,网络通信可分为面向连接和无连接的方式.面向连接是在通信前建立通信链路,而通信结束后释放该链路.无连接的方式则不需要在通信前建立通信连接,这种方式不保证传输的质量. Android提供了多种网络通信的方式,如Java中提供的网络编程,在Android中都提供了支持.Android中常用的网络编程方式如下: 针对TCP/IP协议的Socket和ServerSock

微信红包的架构设计简介

@来源于QCon某高可用架构群整理,整理朱玉华. 背景:有某个朋友在朋友圈咨询微信红包的架构,于是乎有了下面的文字(有误请提出,谢谢) 概况:2014年微信红包使用数据库硬抗整个流量,2015年使用cache抗流量. 微信的金额什么时候算? 答:微信金额是拆的时候实时算出来,不是预先分配的,采用的是纯内存计算,不需要预算空间存储.. 采取实时计算金额的考虑:预算需要占存储,实时效率很高,预算才效率低. 实时性:为什么明明抢到红包,点开后发现没有? 答:2014年的红包一点开就知道金额,分两次操作

JSON 简介

ylbtech-JSON: JSON 简介 JSON:JavaScript Object Notation(JavaScript 对象表示法) JSON是存储和交换文本信息的语法,类似 XML. JSON 比 XML 更小.更快.更易解析. JSON 实例 { "employee":[ {"firstName":"John","lastName":"Doe"}, {"firstName"

Docker简介

Docker简介 什么是Docker: 正所谓Docker的英文本意为"搬运工",所以在我们的世界里,可以理解为Docker搬运的是装满任意类型的APP的集装箱,开发者可以通过Docker将APP变成一种标准化的.可移动植的.自动管理的组件.它用一种新的方式实现了轻量级的虚拟机,专业术语成为应用容器(Application Container) Docker的优势: 1.利用率高 ·Docker对系统资源的利用率很高,一台主机可以同时运行数千个Docker容器 2.可以快速的交付应用程