Ninject简介
?
1.為什么要用Ninject?
Ninject是一個IOC容器用來解決程序中組件的耦合問題,它的目的在于做到最少配置。其他的的IOC工具過于依賴配置文件,需要使用assembly-qualified名稱來進(jìn)行定義,庸長且復(fù)雜常常因為打錯字而破壞程序。這些是他的優(yōu)點,也是為什么要選擇它。Ninject同時不能進(jìn)行熱插拔。
?
2.Ninject做些什么?
其實Ninject做的事情很簡單,說白了就是為我們選擇一個想要的類來處理事務(wù)。來看下面的簡單的例子。
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);}}我們定義了一個實體類,一個接口,一個實現(xiàn)接口的類,這個類完成的功能是計算總價。
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類的構(gòu)造函數(shù)使用接口IValueCalculater實現(xiàn)作為一個準(zhǔn)備DI的參數(shù)。CalculatStockValue方法創(chuàng)建一個Product對象數(shù)組,然后調(diào)用IValueCalculater接口中的ValueProducts來獲得總價。這里可以看到ShoppingCart類中只出現(xiàn)了接口IValueCalculater,卻沒有出現(xiàn)這個接口的實現(xiàn)類LinqValueCalculator,說的直白點就是ShoppingCart中計算的總價是一個影藏的類實現(xiàn)的,我們可以修改這個影藏的類達(dá)到修改總價的目的,而不需要修改ShoppingCart類中的代碼。好的,Ninject做的工作就是和上面的類似,是的,它只能完成這么個工作,不過會有很多的變化,最終目的只有一個,就是決定到當(dāng)前到底要使用哪一個類似LinqValueCalculator著那個的實現(xiàn)類。
?
3.Ninject的使用
關(guān)于如何下載安裝Ninject這里不再說了,網(wǎng)上有很多的資源。這里只說幾個簡單的例子。
IKernel ninjectKernel = new StandardKernel();ninjectKernel.Bind<IValueCalculater>().To<LinqValueCalculator>();上面的代碼將想使用的類型和他的接口進(jìn)行綁定,高祖Ninject,當(dāng)接收到一個實現(xiàn)IValueCalculater的請求的時候,創(chuàng)建病返回LinqValueCalculator這個類,上面的兩個關(guān)鍵字Bind,To可以幫助我們理解他的意思。
IValueCalculater calcImpl = ninjectKernel.Get<IValueCalculater>(); ShoppingCart cart = new ShoppingCart(calcImpl);當(dāng)我們調(diào)用上面兩句的時候就會去計算總價。
下面我們看看他的變形。
1.依賴性鏈
當(dāng)使用ninjectKernel.Get創(chuàng)建一個類型的時候會檢查這個類型與其他類型之間的耦合,如果有額外的依賴性,Ninject會解析這些依賴性,并創(chuàng)建所需要的所有的類的類型。下面我們在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 關(guān)聯(lián)起來。
ninjectKernel.Bind<IDiscountHelper>().To<DefalutDiscountHelper>();IValueCalculater calcImpl = ninjectKernel.Get<IValueCalculater>();
當(dāng)IValueCalculater被請求的時候,Ninject知道它要實例化的是LinqValueCalculator,然后進(jìn)一步考察這個類,并發(fā)現(xiàn)他依賴一個可以解析的接口,Ninject會創(chuàng)建DefaultDiscountHelper的一個實例,并把它注入到LinqValueCalculator類的構(gòu)造器中,一IValueCalculator作為返回結(jié)果,不管這個依賴性鏈有多長,多復(fù)雜,Ninject都會以這種方式檢查它要實例化的每一個依賴性。
2.指定屬性和參數(shù)值
修改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方法來設(shè)置DefalutDiscountHelper 類中的屬性DiscountSize,方法如下
ninjectKernel.Bind<IDiscountHelper>().To<DefalutDiscountHelper>().WithPropertyValue("DiscountSize", 50M); IValueCalculater calcImpl = ninjectKernel.Get<IValueCalculater>();3.指定構(gòu)造函數(shù)的參數(shù)值
如果具體類中有帶參數(shù)的構(gòu)造函數(shù)可以使用WithConstructorArgument方法來指定這個參數(shù),修改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.上面我們都是綁定接口,其實只要是有繼承關(guān)系的兩個類之間也可以進(jìn)行綁定,下面我們來看一個例子,我們先頂一個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綁定同一個接口的多個實現(xiàn),或同一個類的多個派生類,并在不同條件下綁定不同的類。我們可以對當(dāng)前綁定的具體類進(jìn)行判斷,最終綁定另外一個具體類,先來定義一個IValueCalculator的另外一個實現(xiàn)類,代碼如下
public decimal ValueProducts(params Product[] products){decimal totalValue = 0;foreach (Product p in products){totalValue += p.Price;}return totalValue;}下面的代碼將有選擇的創(chuàng)建Ninject類。
ninjectKernel.Bind<IValueCalculater>().To<IterativeValueCalculatgor>().WhenInjectedInto<LimitShoppingCart>();這段代碼的意思是當(dāng)LimitShoppingCart這個類被綁定的時候才將IterativeValueCalculatgor綁定到它的接口中,我們可以將IterativeValueCalculatgor和LimitShoppingCart看做是一套具體的邏輯,是有具體關(guān)系的,例如這是同一次促銷的產(chǎn)品,即他們是為同一此促銷活動而新建的類,這就為我們的業(yè)務(wù)邏輯實現(xiàn)提供一個便利。
?
?3.將Ninject用于ASP.NET MVC
?這部分本人還沒有用到過,是從書本中看到的,也是初次接觸。DefaultControllerFactory類是創(chuàng)建控制器類實例的一個類。先看代碼吧。
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);}}這個類創(chuàng)建了一個Ninject內(nèi)核,用它對控制器類的請求進(jìn)行服務(wù),請求是通過GetControllerInstance方法實現(xiàn)的,它是在MVC框架在需要一個控制器對象時調(diào)用的。我們不需要明確的綁定控制器,可以依靠默認(rèn)的自身綁定特性,因為控制器是從System.Web.Mvc.Controller派生來的具體類。
AddBinding方法允許我們隊存儲庫和希望保持送耦合的組件添加Ninject綁定,也可以吧這個方法用于對需要額外的構(gòu)造器參數(shù)或者屬性的控制器進(jìn)行綁定,說的明白點就是我們上面展示的那些需要自己綁定的類。
創(chuàng)建了這個類可以用MVC框架對它進(jìn)行注冊,在Global.asax類的Application_Start方法中來完成注冊,代碼如下
protected void Application_Start(){AreaRegistration.RegisterAllAreas();RegisterGlobalFilters(GlobalFilters.Filters);RegisterRoutes(RouteTable.Routes);ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());}現(xiàn)在我們使用NinjectControllerFactory來獲得控制器的實例,而Ninject將自動第吧DI運用到控制器對象中。
希望這篇簡單的介紹對你有用。
原文鏈接:http://www.cnblogs.com/tylerdonet/p/3297915.html
轉(zhuǎn)載于:https://www.cnblogs.com/Percy_Lee/p/5333547.html
總結(jié)
- 上一篇: App原生、混合、纯WEB开发模式的优劣
- 下一篇: 【BZOJ1623】 [Usaco200