1.爲何要用Ninject?html
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); } }
咱們定義了一個實體類,一個接口,一個實現接口的類,這個類完成的功能是計算總價。ide
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這裏再也不說了,網上有不少的資源。這裏只說幾個簡單的例子。ui
IKernel ninjectKernel = new StandardKernel(); ninjectKernel.Bind<IValueCalculater>().To<LinqValueCalculator>();
上面的代碼將想使用的類型和他的接口進行綁定,高祖Ninject,當接收到一個實現IValueCalculater的請求的時候,建立病返回LinqValueCalculator這個類,上面的兩個關鍵字Bind,To能夠幫助咱們理解他的意思。this
IValueCalculater calcImpl = ninjectKernel.Get<IValueCalculater>(); ShoppingCart cart = new ShoppingCart(calcImpl);
當咱們調用上面兩句的時候就會去計算總價。spa
下面咱們看看他的變形。
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運用到控制器對象中。
但願這篇簡單的介紹對你有用。
原文連接:http://www.cnblogs.com/tylerdonet/p/3297915.html