主要翻譯自Autofac的官方文檔殖卑。
概念
控制反轉(zhuǎn)背后的思想是帖蔓,與其在程序中把類(lèi)捆綁在一起讓它們“New”出各自的依賴(lài)危彩,不如把它們切割開(kāi)炼杖,使得依賴(lài)在類(lèi)的構(gòu)建被傳遞。
基本實(shí)例
例如有一個(gè)類(lèi)景用,用來(lái)打印當(dāng)前時(shí)間涵叮;但我們不想讓它和Console
捆綁在一起惭蹂,因?yàn)槲覀冞€要測(cè)試它;而且可能還要在Console不可用的場(chǎng)景下使用它割粮。以下是一個(gè)示例盾碗。
Output接口和它的實(shí)現(xiàn),規(guī)定了并實(shí)現(xiàn)了所需要的功能:Write()
public interface IOutput
{
void Write(string content);
}
public class ConsoleOutput : IOutput
{
public void Write(string content)
{
Console.WriteLine(content);
}
}
“寫(xiě)日期”接口及其實(shí)現(xiàn)舀瓢。接收一個(gè)IOutput
廷雅,并把內(nèi)容交給它打印:
public interface IDateWriter
{
void WriteDate();
}
public class TodayWriter : IDateWriter
{
private IOutput _output;
public TodayWriter(IOutput output)
{
this._output = output;
}
public void WriteDate()
{
this._output.Write(DateTime.Today.ToShortDateString());
}
}
在主類(lèi)(客戶(hù)端代碼)內(nèi)京髓,將所需要的類(lèi)注冊(cè)給ContainerBuilder
:
public class Program
{
// Autofac 的 Container 對(duì)象航缀,用來(lái)創(chuàng)建其它對(duì)象
private static IContainer Container { get; set; }
static void Main(string[] args)
{
var builder = new ContainerBuilder();
// 向 Container 注冊(cè)所需的類(lèi)型
builder.RegisterType<ConsoleOutput>().As<IOutput>();
builder.RegisterType<TodayWriter>().As<IDateWriter>();
Container = builder.Build();
// 創(chuàng)建服務(wù)端類(lèi)的實(shí)例并調(diào)用相關(guān)功能的過(guò)程在這個(gè)方法里,下面會(huì)詳細(xì)說(shuō)明堰怨。
WriteDate();
}
}
注冊(cè)好類(lèi)型之后就可以創(chuàng)建對(duì)象了芥玉。創(chuàng)建對(duì)象需要使用生命周期范圍。一個(gè)Container
本身就是一個(gè)生命周期范圍备图,但不應(yīng)該直接用Container
來(lái)創(chuàng)建對(duì)象灿巧,而是先用它來(lái)創(chuàng)建一個(gè)新的生命周期范圍,以便于用完之后關(guān)掉揽涮。
public static void WriteDate()
{
using (var scope = Container.BeginLifetimeScope())
{
var writer = scope.Resolve<IDateWriter>();
writer.WriteDate();
}
}
scope.Resolve<IDateWriter>()
方法用來(lái)創(chuàng)建實(shí)例抠藕。它所要?jiǎng)?chuàng)建實(shí)例的IDateWriter
類(lèi),在實(shí)例化的時(shí)候要求一個(gè)IOutput
實(shí)例蒋困;但我并沒(méi)有將這個(gè)IOutput
實(shí)例傳遞給它幢痘,而是由它自己去創(chuàng)建。這是控制反轉(zhuǎn)框架最核心的功能家破。
這個(gè)過(guò)程大體是這樣的:
-
WriteDate
靜態(tài)方法中,我要求Autofac
創(chuàng)建一個(gè)IDateWriter
實(shí)例购岗; -
Autofac
發(fā)現(xiàn)IDateWriter
映射給了TodayWriter
汰聋,所以就開(kāi)始創(chuàng)建TodayWriter
; -
Autofac
發(fā)現(xiàn)TodayWriter
的構(gòu)造函數(shù)要求一個(gè)IOutput
實(shí)例喊积; -
Autofac
發(fā)現(xiàn)ConsoleOutput
映射給了IOutput
烹困,于是開(kāi)始創(chuàng)建ConsoleOutput
的實(shí)例; -
Autofac
使用這個(gè)新創(chuàng)建的ConsoleOutput
實(shí)例乾吻,完成了TodayWriter
實(shí)例的創(chuàng)建髓梅; -
Autofac
將這個(gè)TodayWriter
實(shí)例返回,就此完成創(chuàng)建IDateWriter
實(shí)例的任務(wù)绎签。
基本實(shí)例的補(bǔ)充
在上面創(chuàng)建實(shí)例的過(guò)程中枯饿,對(duì)于服務(wù)端類(lèi)型全程使用接口,使得在客戶(hù)端代碼中創(chuàng)建實(shí)例的過(guò)程不依賴(lài)于服務(wù)端代碼中的類(lèi)诡必。但在類(lèi)型注冊(cè)(RegisterType()
)的過(guò)程中奢方,還是使用了服務(wù)端的類(lèi)型,所以并沒(méi)有實(shí)現(xiàn)完全的解耦合◇郑可以用配置文件來(lái)代替類(lèi)型引用稿蹲,實(shí)現(xiàn)完全的解耦合。
<configuration>
<configSections>
<section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
</configSections>
<autofac defaultAssembly="AutofacDemo">
<components>
<component type="AutofacDemo.TodayWriter, AutofacDemo" service="AutofacDemo.IDateWriter" />
<component type="AutofacDemo.ConsoleOutput, AutofacDemo" service="AutofacDemo.IOutput" />
...
</components>
</autofac>
</configuration>
這樣在客戶(hù)端代碼中鹊奖,就可以使用配置文件來(lái)完成類(lèi)型的注冊(cè):
var builder = new ContainerBuilder();
// 向 Container 注冊(cè)所需的類(lèi)型
builder.RegisterModule(new ConfigurationSettingsReader("autofac"));
Container = builder.Build();
另外
- 整合列表:關(guān)于如何將Autofac整合到其它程序中苛聘。
- 注冊(cè)內(nèi)容:如何將組件注冊(cè)給Autofac以提高可擴(kuò)展性。
- 通過(guò)Autofac 配置選項(xiàng) 來(lái)更好地管理組件的注冊(cè)忠聚。
- 其它參考頁(yè)面
- 參考:Autofac在mvc 3中的使用
- 參考:Autofac - Getting Started
- 參考:AutoFac - 生如夏花
- 參考:ASP.NET MVC IOC 之AutoFac攻略
以上设哗。