Autofac
Autofac是一套高效的依賴注入框架。javascript
Autofac官方網站:http://autofac.org/java
Autofac在Github上的開源項目:https://github.com/autofac/Autofacgit
Autofac安裝:經過VS的Nuget能夠很方便的獲取。github
IoC/DI
關於IoC與DI的概念,網上有不少相關的博客,你們能夠稍微瞭解一下,對比一下。框架
我我的的理解就是按照英文的中文翻譯來理解的:ide
IoC: Inversion of Control 控制反轉,將控制權進行反轉,將本由自身控制的對象初始化交由外部IoC容器進行初始化;函數
DI: Dependency Injection 依賴注入,將對象依賴的其餘對象,經過注入的方式進行初始化。網站
咱們先經過一個簡單的例子來看看Autofac的基本使用方式以及一些概念:ui
class Program { static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterType<Class_1>(); //將Class_1註冊到Autofac容器中 IContainer container = builder.Build(); Class_1 obj = container.Resolve<Class_1>(); //從autofac容器中獲取Class_1對象 Console.WriteLine(obj.Id); Console.Write("Press any key to continue..."); Console.ReadKey(); } }class Class_1 { public Guid Id { get; set; } public Class_1() { Id = Guid.NewGuid(); } }上面的代碼演示了最簡單註冊/獲取方式。咱們先經過ContainerBuilder進行類型註冊,而後在後面能夠經過IContainer進行獲取類型實例。這裏咱們也明白了一點,類型是須要先進行註冊,而後纔可以經過Autofac進行獲取(後面會談到一些特殊的配置,可是這也屬於另類的註冊方式)。spa
而後咱們能知道在Autofac中,先經過ContainerBuilder進行類型註冊,而後經過ContainerBuilder的Build方法來獲取IContainer類型實例,後面則能夠經過該IContainer實例來獲取註冊類型的實例對象。
類型/泛型註冊
在簡單實例中,咱們已經看到了一種註冊方式,那就是泛型註冊:
builder.RegisterType<Class_1>();這種註冊方式很方便也很簡單,比較經常使用,可是有一個缺點就是,註冊的類型必須在當前項目或被當前項目引用,由於使用泛型,必須類型明確。針對這點,還有一種經過Type對象進行註冊的方式:
//字符串爲類型徹底名稱 builder.RegisterType(Type.GetType("AutofacBlog.Class_1"));使用這種方式進行類型註冊,被註冊的類型能夠不是被直接引用,可是注意,類型所在的程序集必須被加載。
這種註冊方式,在有插件或相似須要動態加載程序集的狀況下比較使用,經過掃描程序集,獲取一些知足指定條件的類型,來進行註冊。
程序集批量註冊
類型註冊中提到了經過掃描程序集,來獲取部分類型進行註冊。Autofac對此提供了一個方便的方式,能夠直接經過程序集來篩選類型註冊:
//獲取當前應用程序加載程序集(C/S應用中使用) var assembly = Assembly.GetExecutingAssembly(); var builder = new ContainerBuilder(); builder.RegisterAssemblyTypes(assembly); //註冊全部程序集類定義的非靜態類型上述代碼中,經過RegisterAssemblyTypes方法,將assembly中全部自定義的非靜態類型都註冊到Autofac中,後面可使用IContainer對象獲取全部該程序集中自定義的類型對象。
這種方式達到了批量的效果,可是一般,咱們並不須要把全部的類型都進行註冊,因此Autofac提供了幾種過濾方式:
builder.RegisterAssemblyTypes(assembly) .Where(type => type.Namespace.Equals("IocAutofac.Example")); //條件判斷這種方式相信你們都比較熟悉,Where+lambda的方式來進行條件判斷,lambda參數爲Type類型,也就是程序集中的type。
builder.RegisterAssemblyTypes(assembly) .Except<Program>(); //排除Program類型這種方式用來排除指定類型的註冊,當排除的個例比較少時,會比較適用。Except還有另外一種用法,可是用法比較複雜,在此不進行介紹。
builder.RegisterAssemblyTypes(assembly) .InNamespace("IocAutofac.Example"); //類型在IocAutofac.Example命名空間中被註冊的類型須要在指定命名空間中。
builder.RegisterAssemblyTypes(assembly) .InNamespaceOf<Program>(); //類型在Program所在的命名空間中*/這種方式與上面一種方式比較類似,也是用來判斷命名空間的,這種方式是根據類型來獲取命名空間。
經過這種方式,咱們能夠對程序集中的類型進行批量註冊,類型/泛型方式在被註冊類型較少的狀況下仍是不錯的,但當被註冊類型不少的時候,一個一個的手寫註冊會顯得很無力,這時候就是程序集批量註冊顯威的時候了。
Lambda註冊
上面講到的兩種方式都是經過類型進行直接註冊的,這種註冊方式,在獲取時,會直接經過構造函數new出對象(關於構造函數的優選選擇在後面的博文中將進行說明),不會作更多的操做。有時,咱們但願可以在獲取對象時可以自動的作更多的事情時,咱們能夠經過Lambda註冊來解決:
builder.Register(cc => { var clas1 = new Class_1(); while (clas1.Id.ToString().Contains("a")) { clas1.Id = Guid.NewGuid(); } return clas1; });上述代碼,實際註冊了Class_1類型,由於最後返回的對象類型爲Class_1。
Register方法接收了一個lambda表達式做爲參數,在lambda表達式中,咱們能夠作不少事,包括一些屬性注入(後續說明)、方法注入(後續說明)、條件判斷等等。
咱們在經過Autofac獲取Class_1對象時,實際會執行這樣的一個表達式。另外,lambda表達式的參數cc的類型是IComponentContext,這裏咱們能夠簡單的當作IContainer進行使用。
實例註冊
var clas1 = new Class_1(); clas1.Id = Guid.Empty; builder.RegisterInstance(clas1);經過RegisterInstance進行實例註冊,進行實例註冊時,咱們須要注意,實例註冊能夠做爲一種單例註冊的方式,也就是在後面經過Autofac獲取Class_1對象時,獲取到的是註冊時的那個對象。而且,若是一個在某處修改了該對象,其餘地方再獲取時,獲取到的就是修改後的對象。
Module註冊
在平常開發中,可能不一樣開發會負責不一樣的模塊進行單獨開發。在開發過程當中,不一樣模塊不一樣開發可能都有本身的類型須要註冊到autofac中,可是若是每一個人在註冊時,都去修改一個指定地方的代碼,這在進行代碼合併時,是使人痛苦的。更好的方式是,每一個開發不一樣的模塊都有本身指定的類型註冊區域,這樣,在代碼合併時,會減小不少代碼衝突。
對於這種方式,Autofac已經爲咱們提供了:
class Program { static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterModule<ModuleA>(); //這兩種註冊方式達到的效果都同樣 builder.RegisterModule(new ModuleB()); IContainer container = builder.Build(); Class_1 clas1 = container.Resolve<Class_1>(); Class_2 clas2 = container.Resolve<Class_2>(); Console.WriteLine(clas1.Id); Console.WriteLine(clas2.ToString()); Console.Write("Press any key to continue..."); Console.ReadKey(); } } class ModuleA : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterType<Class_1>(); } } class ModuleB : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterType<Class_2>(); } }class Class_2 { }上述代碼中,有兩個繼承自Module類的類:ModuleA、ModuleB,這兩個類型重寫了父類的Load方法,並在load方法中,分別註冊了Class_1與Class_2類型。而後在主程序中,經過RegisterModule對Module進行註冊。
經過這種方式,不一樣的開發就能夠各自建立一個類繼承自Module,而後重寫Load方法,在Load方法進行本身的類型註冊,最後再進行Module的統一註冊。
Module注意說明
實際上,RegisterModule須要的參數,並非繼承自Module類的,而是實現了IModule接口的類,而Module也是實現了IModule接口的。也就是咱們也能夠寫一個實現了IModule接口的類型,而後在RegisterModule時傳入。可是通常咱們直接去繼承Module就行了,這種方式比較簡單方便,實現IModule的方式更爲複雜,固然,功能也更多,在此就不進行介紹了。
程序集Module註冊
Module註冊,爲多人開發提供了一種方便的註冊方式,可是咱們也能夠發現,這種方式,仍是會須要手動註冊Module,若是Module過多,Module註冊代碼也會顯得多而雜,固然,能夠經過人工管理來控制Module的量。可是Autofac還提供了一種更方便的方式,而且,對於相似Orchard的模塊開發(子模塊與主模塊無引用關係,經過程序集加載方式來加載子模塊)或是插件開發,咱們沒辦法經過Registerodule來註冊無直接引用關係的Module。
對於上述的狀況,Autofac提供了很好的方式來解決:
var builder = new ContainerBuilder(); var assembly = Assembly.GetExecutingAssembly(); builder.RegisterAssemblyModules(assembly);上述代碼會註冊assembly程序集中全部實現了IModule接口的類型(多層繼承也算),這樣,咱們只須要將取出全部程序集,而後經過RegisterAssemblyModules進行一次性註冊,就能夠自動註冊全部Module了。
RegisterAssemblyModule還能夠指定一個泛型類型:
builder.RegisterAssemblyModules<ModuleA>(assembly);這樣註冊,是指定只註冊assembly程序集中繼承自ModuleA的Module。
本篇博文主要講述Autofac中比較經常使用也比較好用的註冊方式,並無把全部的註冊方式都講述出來。
我的很是推薦使用Module,每一個項目擁有本身的一個Module,這樣的一個Module都有固定的未知,便於查找該項目中的註冊及依賴關係。
經過本篇博文,能夠了解到幾種經常使用的註冊方式,以及最簡單的對象獲取方式,初學者能夠簡單的試試。
本篇博文講述的內容可能與你們平時使用autofac的方式不同,平時使用時還會使用As,可是我我的認爲這個不屬於單純註冊的內容,因此將這部分放到後面的博文中。