autofac
Autofac是一套高效的依賴注入框架。javascript
Autofac官方網站:http://autofac.org/html
Autofac在Github上的開源項目:https://github.com/autofac/Autofacjava
Autofac安裝:經過VS的Nuget能夠很方便的獲取。git
類型關聯(服務暴露)
關於「類型關聯(服務暴露)」這個名字,是源於官網上的exposes一詞,有點詞窮,但願你們在看完博客後可以提供更加貼切的描述名稱。github
前面的autofac系列文章一直有提到直接註冊類型並非autofac已經依賴注入的主要使用方式,最佳的依賴注入與autofac的使用方式,都是要結合面向接口(抽象)編程的概念的。咱們推崇的是依賴於抽象而不是具體,關於這點,我在上一篇博文最後的總結中有簡單的說明。編程
瞭解autofac的朋友在看前面的博文的時候,可能會以爲很彆扭,由於沒有使用As<>。可是博主以爲依賴注入並非必定要與接口或抽象類關聯在一塊兒才能算依賴注入,博主是想將依賴注入與面向抽象編程稍稍分離開來,在你們理解依賴注入的概念後再來與面向抽象編程概念相結合,這樣對於初學者可能更方便吸取。後面的博客實例代碼也會根據實際狀況來決定是否使用類型關聯(服務暴露),一切從簡了。數組
As關聯
關於類型關聯(服務暴露)的內容其實並很少,咱們在進行手動關聯時,基本都是使用As進行關聯的。咱們先來看看一個實例吧:框架
class Program { static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterType<Class1>().As<IInterface>(); var container = builder.Build(); IInterface inter = container.Resolve<IInterface>(); Console.WriteLine(inter.Id); Console.Write("Press any key to continue..."); Console.ReadKey(); } }interface IInterface { Guid Id { get; } } class Class1 : IInterface { private Guid _id; public Guid Id { get { return _id; } } }從代碼中能夠看到,咱們直接在類型註冊後加了一句As<…>(),而後咱們在使用Resolve時,咱們也是用的As的類型。網站
讓咱們回顧一下以前的用法,以前是直接RegisterType,最後註冊的類型是Class1,Resolve時,也是直接用Class1。而如今註冊的雖然仍是Class1,可是獲取時倒是用IInterface,而且最後獲取到的實例類型是Class1。這樣看有點繞,代碼層面上是這樣的,但咱們也能夠理解爲註冊了IInterface,可是爲IInterface指定了實現。這樣作的好處在於,咱們若是但願更改IInterface的實現,只須要修改註冊的代碼,而不須要修改獲取處以及後續使用IInterface實例的代碼。ui
As還有兩種重載,一種是Type可變數組,另外一種是Service可變數組。第二種方式咱們通常不用,autofac底層使用,推薦篇不進行說明。
這裏使用RegisterType進行註冊的,一樣,其餘註冊方式也可使用As進行類型關聯。
多關聯
一個類可能實現多個接口,若是咱們但願Resolve多個接口時獲取到的都是那個類型,應該怎麼作呢?最容易想到的方式就是直接再註冊As一遍就行了。嗯,這樣確實是能夠的,可是你們是否記得IEnumerable和IQueryable那種鏈式編程的方式不?autofac一樣有這樣簡便的方式,若是但願多個接口或類型都與同一個類型進行關聯,咱們能夠直接再表達式後面繼續As:builder.RegisterType<C1>().As<I1>().As<I2>().As<I3>,如此,Resolve<I1>、Resolve<I2>、Resolve<I3>獲取到的都是C1類型實例。
自關聯AsSelf
As使用注意
不使用As時,RegisterType註冊的是什麼類型,Resolve就使用什麼類型進行獲取,可是在使用As後,就只能使用As的類型進行Resolve。好比前面的例子中,只可以Resolve<IInterface>,而不能Resolve<Class1>,不然將拋出異常。
可是若是還想在Resolve<Class1>時可以獲取到Class1而不拋出異常,應該怎麼辦呢?在不知道AsSelf方法的狀況下,能夠在註冊時直接As<Class1>,這樣就能夠了。另外一種方式就是AsSelf了:
// 這兩句代碼效果相同 builder.RegisterType<Class1>().As<IInterface>().As<Class1>(); builder.RegisterType<Class1>().As<IInterface>().AsSelf();相對而言,不論什麼類型,最後只需AsSelf就好了,這樣相對方便,可是具體仍是要看我的習慣了。
批量關聯AsImplementedInerfaces
根據這個方法的名稱,咱們大概可以猜出它的做用了,AsImplementedInterfaces也就是直接與類型實現的接口進行類型關聯。好比有如下類型定義:
interface I1 { } interface I2 { } interface I3 { } interface I4 { } interface I5 { } interface I6 { } interface I7 { } class C1 : I1, I2, I3, I4, I5, I6, I7 { }一個類型實現了7個接口,而後咱們但願Resolve這七個中任何一個接口,都能獲取到C1實例,按照咱們第一節中說的多關聯,代碼能夠簡寫爲:
builder.RegisterType<C1>() .As<I1>().As<I2>() .As<I3>().As<I4>() .As<I5>().As<I6>() .As<I7>();雖然這個代碼相對RegisterType屢次再屢次As簡潔了不少,可是仍是不夠簡潔,然而在有AsImplementInterfaces方法後,就可以很是簡單:
builder.RegisterType<C1>().AsImplementedInterfaces();在程序集註冊這種方式中,AsImplementInterfaces更能顯示出威力,程序集註冊這種方式中,都是批量註冊類型的,批量註冊的這些類型,它們可能都實現了不一樣的接口,這樣咱們沒辦法爲它們一一關聯接口,可是經過AsImplementInterfaces方法,可讓全部註冊類型自動與實現的接口進行關聯。固然,也正由於這點,在使用AsImplementInterfaces時須要注意,是否真的但願與全部接口都進行關聯。
一個接口/類型只能與一個類型進行關聯
在前面咱們看到了,能夠將一個類型與多個接口進行關聯,讓多個接口Resolve結果都是同一個類型實例。須要注意的是,這個是不可逆的,也就是一個接口不能與多個類型進行關聯,由於這樣autofac不知道應該返回哪一個類型實例。代碼實例:
builder.RegisterType<C1>().As<I>(); // class C1 : I builder.RegisterType<C2>().As<I>(); // class C2 : Iinterface I { } class C1 : I { } class C2 : I { }按上面的代碼,最後實際與I接口關聯的類型是C2,autofac中按註冊順序,後面註冊的會覆蓋前面註冊的。若是想要阻止這種默認行爲(相同接口/類型進行屢次類型關聯,後面的關聯覆蓋前面的關聯),能夠在As方法調用用繼續調用PreserveExistingDefaults方法,這樣,若是以前該接口/類型已經進行關聯註冊,則這次關聯無效:
builder.RegisterType<C1>().As<I>(); // class C1 : I builder.RegisterType<C2>().As<I>().PreserveExistingDefaults(); // class C2 : I上面的代碼,經過Resolve<I>()獲取到時C1類型實例。
一個接口關聯多個類型注意
這裏說的一個接口不能關聯多個類型,是針對這種經常使用的註冊及關聯。其實能夠經過Named<>、Meta<>這種方式進行多關聯,關於此類話題後續博文將會談到。
關聯類型與註冊類型須要時繼承/實現關係或爲其自己
builder.RegisterType<X>().As<Y>();當這樣進行註冊關聯時,須要X繼承或實現Y,再或者Y就是X類型,不然將在builder調用Build方法時拋出異常。
看完本篇博文,autofac最基本/經常使用的功能就完結了。可是如今只是最基本的功能,推薦篇並無結束,還有一些內容,我認爲仍是須要掌握的,但願你們繼續關注,謝謝!