AutoFac文檔
目錄
- 開始
- Registering components
- 控制范圍和生命周期
- 用模塊結構化Autofac
- xml配置
- 與.net集成
- 深入理解Autofac
- 指導
- 關於
- 詞匯表
Registering components
ComponentCreation
http://code.google.com/p/autofac/wiki/ComponentCreation
autofac容器提供多個內置參數用來創造Component。
Component可以通過兩種方式被創建:
- lambda表達式(通過反射)
- 提供一個現成的實例
ContainerBuilder 提供了 Register() 一類的方法去創建 Component。
ContainerBuilder使用 As 方法將Component封裝成了服務使用。
var builder = new ContainerBuilder(); builder.RegisterType<ConsoleLogger>().As<ILogger>(); builder.RegisterType<NHPersonRepository>().As<IFindPerson, IRepository<Person>>();
使用 As() 方法將Component的默認服務覆蓋掉.所以
container.Resolve<ILogger>();
上面的語法會成功.但是
container.Resolve<ConsoleLogger>();
不會.
反射
AutoFac能夠通過反射檢查一個類型,選擇一個合適的構造函數,創造這個對象的實例. RegisterType<T>() 和 RegisterType(Type) 兩個方法以這種方式建立.
builder.RegisterType<A>(); // Create A using reflection builder.RegisterType(typeof(B)); // Non-generic version
選擇構造函數和實例化依賴的過程會在后面的原理中講述.
默認服務
通過反射創造的默認實例會是默認實現類型(A above will provide the service A)
表達式
發射對於component創建來說是個很不錯的默認選擇.事情變得亂七八糟盡管component創建邏輯建立在簡單的構造函數上.
Autofac接受一個委托或者lambda表達式用來創建component.
builder.Register(c => new A(c.Resolve<B>()));
表達式中的參數 c 是創建component的容器.使用這種方式而不是閉包()去訪問容器非常重要.這確保了精確配置(DeterministicDisposal)和嵌套容器可以被正確支持.
使用這個參數可以滿足額外的依賴,比如在這個例子中A需要B作為構造參數.
下面是一些用反射創建component的一些例子(很糟糕的需求)
復雜的參數
構造函數的參數不能使用簡單的常量定義.與其困惑於如何在XML配置文件中構造一個特定類型的值,不如使用C#:
builder.Register(c => new UserSession(DateTime.Now.AddMinutes(25)));
(當然session的終結是你很有可能想在xml配置文件中制定的)
屬性注入
這是推薦的屬性初始化方式. IComponentContext.ResolveOptional() 很方便:
builder.Register(c => new A(){ MyB = c.ResolveOptional<B>() });
或者, PropertiesAutowired() 這個方法也可以導致屬性注入.
builder.RegisterType<X>().PropertiesAutowired();
不管怎樣,在大多數情況下不推薦使用屬性注入.替代的選擇像 Null Object -使用構造函數注入重載構造函數或者構造函數參數默認值來創造一個干凈的,"不變的"components.
根據參數來選擇實現方法
使用IOC容器創建對象的最大好處之一就是一個類型可以被實例化成不同的實例,這通常體現在運行階段,而不是配置階段.
builder.Register<CreditCard>((c, p) => { var accountId = p.Named<string>("accountId"); if (accountId.StartsWith("9")) return new GoldCard(accountId); else return new StandardCard(accountId); });
在這個例子中,信用卡被是實例化成兩個類:金卡和普通卡.這是由運行時段提供的卡ID決定的.
在這個例子中,一個可選的參數P被提供給構造函數.
可以像下面這樣使用這種注冊方法來獲得實例:
var card = container.Resolve<CreditCard>(new NamedParameter("accountId", "12345"));
當使用委托工廠或者使用一個委托來創建CreditCard的實例時,可以使語言清晰,而且是強類型的.
Default Service
使用這種表達式創建的component默認值是由表達式推導出來的.
提供的實例(Provided Instances)
有時候我們需要將autofac集成到一個系統中.在很多情況下,我們需要在容器中使用一些已經在系統存在的單例對象的實例.這時就不能創造一個單例的component(因為這些對象已經在系統中存在了),而是應該在容器中將它們注冊為實例:
builder.RegisterInstance(MySingleton.Instance).ExternallyOwned();
這種方法會確保系統中的單例實例最終轉化為由容器托管的單例實例.
Default Service
默認值就是注冊的那個實例
開放的泛型類型
autofac支持開放的泛型類型.使用 RegisterGeneric() 這個方法:
builder.RegisterGeneric(typeof(NHibernateRepository<>)) .As(typeof(IRepository<>)) .InstancePerLifetimeScope();
當從容器中請求一個匹配的類型時,autofac會自動匹配一個等價的具體實現類型.
// Autofac will return an NHibernateRepository<Task> var tasks = container.Resolve<IRepository<Task>>();
注冊一個具體的類型((e.g. IRepository<Person> )會覆蓋掉上面的泛型注冊.
默認的注冊
如果一個類型被多次注冊,以最后注冊的為准.
為避免各種情況,可以使用 PreserveExistingDefaults() 修飾符
builder.Register<X1>().As<IX>(); builder.Register<X2>().As<IX>().PreserveExistingDefaults();
在這種情況下,X1會是IX的默認值.(如果不適用 PreserveExistingDefaults() 修飾符,X2會是默認值,因為它是最后被注冊的)