autofac
Autofac是一套高效的依賴注入框架。html
Autofac官方網站:http://autofac.org/git
Autofac在Github上的開源項目:https://github.com/autofac/Autofacgithub
Autofac安裝:經過VS的Nuget能夠很方便的獲取。框架
依賴注入
依賴注入,這個專業詞咱們能夠分爲兩個部分來理解:學習
依賴,也就是UML中描述事物之間關係的依賴關係,依賴關係描述了事物A在某些狀況下會使用到事物B,事物B的變化會影響到事物A;網站
注入,醫生經過針頭將藥物注入到病人體內。注入也就是由外向內注入、灌輸一些東西。ui
綜合上面的說明,依賴注入就是A類依賴B類,B類的實例由外部向A注入,而不是由A本身進行實例化或初始化。this
構造器注入
咱們先理解構造器注入的字面意思,構造器注入也就表示,依賴關係經過構造器進行注入。spa
這種咱們平時是很是常見的,類A依賴於類B,類A的構造方法中,有一個參數爲類B,在new 類A,會從外部爲類B傳入實例,這就是構造注入:code
class Program { static void Main(string[] args) { var b = new B(); var a = new A(b); } } class A { private B _b; public A(B b) { this._b = b; } } class B { }上面說明了構造注入的含義以及構造注入的表現形式,下面咱們來看看autofac中的構造注入。
還記得在上一篇博文Autofac全面解析系列(版本:3.5) – [使用篇(推薦篇):2.解析獲取] 中的Resolve對象構造方法選擇原則小結中提到了構造注入這個概念。在使用autofac時,構造注入是默認行爲。
以上面的代碼爲例,若是類型A和類型B都註冊到了autofac中,那麼在經過autofac解析獲取A時,autofac會檢測到A的構造方法中是要一個參數B,而類型B是已經註冊到autofac中的,因此autofac會自動建立b參數,而後傳入A的構造方法中的。這樣,autofac就自動幫咱們完成了構造注入的工做。
class Program { static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterType<A>(); builder.RegisterType<B>(); var container = builder.Build(); var a = container.Resolve<A>(); //A的構造方法須要參數b,可是這裏不須要作更多地操做 } }class A { private B _b; public A(B b) { this._b = b; } } class B { }
屬性注入
屬性注入也就是經過屬性進行注入,咱們修改上面的A類,將變量_b經過屬性暴露出來,而且刪掉有參構造方法,而後讓咱們看看咱們日常寫代碼時怎麼實現屬性注入的:
class Program { static void Main(string[] args) { var a = new A(); //點擊A查看A類修改後結構 var b = new B(); a.B = b; //經過屬性來注入具備依賴關係的B } }class A { private B _b; public B B { get { return _b; } set { _b = value; } } } class B { }這種代碼在平常中咱們寫過了無數遍,即便是這麼日常的代碼,但這就是屬性注入。
依賴注入注意點
可是有一點仍是要注意的,咱們不能隨便把這種相似的代碼拿出去就告訴別人,咱們須要注意一點,須要分清二者之間是否真的是依賴關係。好比領域模型,簡單的領域模型就是將數據表映射爲一個類,對於數據表的每一個字段,咱們會生成一個對應的屬性,對於這種,咱們不可以在爲每一個屬性進行賦值時就說「這是依賴注入」,這並非依賴注入,更多狀況下,字段與表的關係是一個組合關係。這一點對於以前的構造注入和後面會講到的方法注入都適用。
說完注意點,讓咱們再來看看autofac是怎麼進行屬性注入的:
自動屬性注入
屬性注入的全部注入方式都是在註冊時定義的,不像構造注入那般,能夠在Resolve時傳參注入。
構造器注入是默認行爲,不須要設置,默認會去檢查,而屬性注入並非默認行爲。可是咱們能夠經過設置,讓屬性注入也成爲自動注入。
class Program { static void Main(string[] args) { var builder = new ContainerBuilder(); // 經過PropertiesAutowired制定類型A在獲取時會自動注入A的屬性 builder.RegisterType<A>().PropertiesAutowired(); builder.RegisterType<B>(); var container = builder.Build(); var a = container.Resolve<A>(); Console.Write("Press any key to continue..."); Console.ReadKey(); } }使用PropertiesAutowired也只是能指定某個類會自動進行屬性注入,沒有一鍵設置全部類型都會自動注入屬性的設置。並且還須要注意一點,設置了自動屬性注入後,也不表明全部屬性都會自動注入,只有註冊到Autofac中的類型才能自動注入。
WithProperty、WithProperties
PropertiesAutowired方式會自動注入全部能夠注入的屬性,可是若是隻想注入指定幾個屬性,可使用除PropertiesAutowired之外的幾種注入方式,WithProperty就是其中一種:
class Program { static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterType<A>().WithProperty(new NamedPropertyParameter("B", new B())); // builder.RegisterType<A>().WithProperty("B", new B()); //效果與上面相同
var container = builder.Build(); var a = container.Resolve<A>(); Console.Write("Press any key to continue..."); Console.ReadKey(); } }用法簡單,WithProprtties的使用方式與WithProperty類似,在此就不貼代碼了。
lambda
在註冊篇裏面有講到一種lambda註冊方式,lambda註冊時,由於是寫lambda表達式進行註冊,其lambda內容能夠寫不少,其中就能夠進行屬性注入:
var builder = new ContainerBuilder(); builder.Register(c => { var _a = new A(); _a.B = new B(); //手動注入 return _a; });這裏的注入,就是最開始講到屬性注入時的那種賦值注入。
事件
在autofac中,還有一些事件,這些事件在不一樣時期觸發,事件相關的具體內容將在後續說明。在注入中可以使用到的事件有OnActivating和OnActivated,他們是在對象Resolve出來後觸發,能夠在事件中修改或替換返回對象,一樣也能夠進行屬性注入:
var builder = new ContainerBuilder(); builder.RegisterType<A>().OnActivating(e => { e.Instance.B = new B(); //Instance爲Resolve出來的實例,類型爲A });OnActivated事件的寫法與OnActivating相同,關於兩個事件的區別,將在後續博文中進行說明,請持續關注!
方法注入
方法注入也不是默認行爲,並且尚未提供像屬性注入那樣的自動注入設置。
方法注入有兩種方式,也就是屬性注入的後兩種方式:lambda以及事件。你們應該已經可以想到注入的代碼是什麼樣了:
var builder = new ContainerBuilder(); // lambda builder.Register(cc => { var _a = new A(); _a.MethodInjection(new B()); return _a; }); // 事件 builder.RegisterType<A>().OnActivated(e => { e.Instance.MethodInjection(new B()); });MethodInjection爲A的一個方法,而且它須要一個類型爲B的參數,咱們在外部經過方法的方式將B傳入,這就是方法注入。這裏須要特別貼一下A類型的代碼,相對以前有所改動,不只僅是添加了一個方法:
class A { public void MethodInjection(B b) { // 作一些操做 } }這段代碼可能與一些朋友想象中的不同,有些朋友可能想着A中還有一個成員_b,而後在方法MethodInjection中將b賦值給_b。這裏我特地將成員_b去掉,爲的就是說明一個問題:
不是兩個類型之間必定是成員關係,而後纔能有依賴注入,咱們得理解依賴的含義。A類型在某些操做中須要使用到B類型,而並不將B類型持久的保存起來,臨時使用也是一種依賴關係。關於爲何這樣就算做依賴注入,在咱們瞭解剛剛說的依賴關係後,再來看看依賴的注入與不注入的不一樣形式,若是不是注入的方式,那麼B類型將不作爲參數傳入,而直接在方法中new。
而依賴注入的好處,在這裏還不能很好的看到,由於如今是在講autofac中關於注入的方式。若是想更只管的看到注入的好處,咱們將參數B換成接口IClass,使用注入的方式,咱們在外部傳入IClass的實例,由於IClass是接口,咱們能夠傳入不一樣的實現,在更換實現時,這個方法內部的代碼是不須要改動的,反之是須要改動的。依賴注入的好處,咱們點到爲止了,主要仍是要在平常多使用對比,這樣才能更切身的體會它的美妙之處!
疑問
關於注入這塊兒,其實我我的有個疑問,關於autofac。屬性注入中,咱們能夠經過設置PropertiesAutowired進行自動注入,可是有時,可能大部分屬性咱們都但願可以自動注入,然而有時會有那麼幾個屬性咱們須要自動注入忽略掉他們,在我想來,應該是有一個Attribute用於標記屬性,被標記的屬性會在屬性自動注入時被忽略。
而我想的這種Attribute,我找了找,autofac中貌似並沒看到。也多是我本身忽略掉了,若是你們誰有知道的,煩請指導一下,謝謝
尾述
我的仍是推薦使用默認最簡單的構造注入,不須要傳參的那種;屬性注入推薦設置自動屬性注入,若是可以找到疑問中說到的那種Attribute,那就更好了;方法注入仍是不怎麼推薦的。
其實這裏的推薦原則是這樣的,須要在註冊時進行指定注入的方式實際是不太好的,由於後來的人可能不太清楚每一個類型的注入規則,還須要到註冊的地方進行查看,並且不一樣人員寫的不一樣,這樣容易混亂。而在獲取時進行注入,實際也是不太妥的,由於在實際的用法中,咱們會將註冊類型與接口進行關聯,在獲取時直接獲取接口類型。也正由於咱們獲取時獲取的是接口類型,咱們沒法保證接口的實際實現是否是具備咱們預期的參數。
若是有任何問題,還但願你們可以提出討論,互相學習。也但願可以有前輩對博客的內容及表達方式提出意見和建議,謝謝!