前面的學習一直使用的是直接註冊類型並非Autofac已經依賴注入的主要使用方式,最佳的依賴注入與Autofac的使用方式,都是要結合面向接口(抽象)編程的概念的。推崇的是依賴於抽象而不是具體編程
public interface IPerson { void Say(); } public class Worker : IPerson { public void Say() { Console.WriteLine("工人!"); } } public class Student : IPerson { public void Say() { Console.WriteLine("學生!"); } } public class AutoFacManager { IPerson person; public AutoFacManager(IPerson MyPerson) { person = MyPerson; } public void Say() { person.Say(); } }
使用AS進行關聯函數
//IPerson類型的服務和Worker的組件鏈接起來,這個服務能夠建立Worker類的實例 builder.RegisterType<Worker>().As<IPerson>(); using (var container = builder.Build()) { var obj = container.Resolve<IPerson>(); obj.Say(); }
多關聯學習
public interface IPerson { void Say(); } public interface IDuty { void Write(); } public class Worker : IPerson, IDuty { public void Say() { Console.WriteLine("工人!"); } public void Write() { Console.WriteLine("個人工做內容是搬磚!"); } }
一個類可能實現多個接口,若是咱們但願Resolve多個接口時獲取到的都是那個類型,應該怎麼作呢?最容易想到的方式就是直接再註冊As一遍就行了。Autofac提供了相似IEnumerable和IQueryable鏈式編程的方式,若是但願多個接口或類型都與同一個類型進行關聯,咱們能夠直接在表達式後面繼續Asui
builder.RegisterType<Worker>() .As<IPerson>() .As<IDuty>(); using (var container = builder.Build()) { var obj1 = container.Resolve<IPerson>(); var obj2 = container.Resolve<IDuty>(); obj1.Say(); obj2.Write(); }
不使用As時,RegisterType註冊的是什麼類型,Resolve就使用什麼類型進行獲取,可是在使用As後,就只能使用As的類型進行Resolve;可是若是還想在Resolve<Worker>時可以獲取到Worker而不拋出異常,應該怎麼辦呢?在不知道AsSelf方法的狀況下,能夠在註冊時直接As<Worker>,這樣就能夠了。另外一種方式就是AsSelfspa
builder.RegisterType<Worker>().As<IPerson>();//這麼寫獲取實例必須使用As類型進行Resolve builder.RegisterType<Worker>().As<IPerson>().AsSelf();//這麼寫可使用原類型進行Resolve using (var container = builder.Build()) { var obj1 = container.Resolve<Worker>();//builder.RegisterType<Worker>().As<IPerson>().As<Worker>();或者builder.RegisterType<Worker>().As<IPerson>().AsSelf();均可以 var obj2 = container.Resolve<IPerson>();//必須builder.RegisterType<Worker>().As<IPerson>(); obj1.Say(); obj2.Say(); }
以前說到能夠經過多個As爲一個類型關聯多個接口,可是若是實現接口過多代碼仍是不夠簡潔,經過AsImplementInterfaces方法,可讓全部註冊類型自動與實現的接口進行關聯。固然,也正由於這點,在使用AsImplementInterfaces時須要注意,是否真的但願與全部接口都進行關聯設計
builder.RegisterType<Worker>().AsImplementedInterfaces(); using (var container = builder.Build()) { var obj1 = container.Resolve<IPerson>(); var obj2 = container.Resolve<IDuty>(); obj1.Say(); obj2.Write(); }
一個接口/類型只能與一個類型進行關聯,前面咱們看到了,能夠將一個類型與多個接口進行關聯,讓多個接口Resolve結果都是同一個類型實例。須要注意的是,這個是不可逆的,也就是一個接口不能與多個類型進行關聯,由於這樣autofac不知道應該返回哪一個類型實例code
builder.RegisterType<Worker>().As<IPerson>(); builder.RegisterType<Student>().As<IPerson>(); using (var container = builder.Build()) { var obj = container.Resolve<IPerson>(); obj.Say(); }
最後實際與I接口關聯的類型是Student,Autofac中按註冊順序,後面註冊的會覆蓋前面註冊的。若是想要阻止這種默認行爲(相同接口/類型進行屢次類型關聯,後面的關聯覆蓋前面的關聯),能夠在As方法調用用繼續調用PreserveExistingDefaults方法,這樣,若是以前該接口/類型已經進行關聯註冊,則這次關聯無效component
builder.RegisterType<X>().As<Y>();
當這樣進行註冊關聯時,須要X繼承或實現Y,再或者Y就是X類型,不然將在builder調用Build方法時拋出異常。blog
一、類型繼承
類型是描述服務的基本方法
builder.RegisterType<Worker>().As<IPerson>(); //IPerson類型的服務和Worker的組件鏈接起來,這個服務能夠建立Worker類的實例
二、名字
服務能夠進一步按名字識別。使用這種方式時,用 Named()註冊方法代替As()以指定名字
builder.RegisterType<Worker>().Named<IPerson>("worker"); builder.RegisterType<Student>().Named<IPerson>("student"); using (var container = builder.Build()) { var obj1 = container.ResolveNamed<IPerson>("worker"); obj1.Say(); var obj2 = container.ResolveNamed<IPerson>("student"); obj2.Say(); }
三、鍵
有Name的方式很方便,可是值支持字符串,但有時候咱們可能須要經過其餘類型做鍵。
例如,使用枚舉做爲key:
public enum State { Worker, Student }
builder.RegisterType<Worker>().Keyed<IPerson>(State.Worker); builder.RegisterType<Student>().Keyed<IPerson>(State.Student); using (var container = builder.Build()) { var obj1 = container.ResolveKeyed<IPerson>(State.Worker); obj1.Say(); var obj2 = container.ResolveKeyed<IPerson>(State.Student); obj2.Say(); }
ResolveKeyd()會致使容器被當作 Service Locator使用,這是不被推薦的。應該使用IIndex type替代。
IIndex索引,須要using Autofac.Features.Indexed
Autofac.Features.Indexed.IIndex<K,V>是Autofac自動實現的一個關聯類型。component可使用IIndex<K,V>做爲參數的構造函數從基於鍵的服務中選擇須要的實現
builder.RegisterType<Student>().Keyed<IPerson>(State.Student); using (IContainer container = builder.Build()) { IIndex<State, IPerson> IIndex = container.Resolve<IIndex<State, IPerson>>(); IPerson p = IIndex[State.Student]; p.Say(); }
IIndex中第一個泛型參數要跟註冊時一致,在例子中是State枚舉。其餘兩種註冊方法沒有這樣的索引查找功能,這也是爲何設計者推薦Keyed註冊的緣由之一