Autofac学习(一)
开始
首先我们根据官方的文档做一个例子,来体验一下:
首先安装Autofac包
Autofac
- 按照控制反转(IoC)的思想构建你的应用程序
- 添加Autofac引用
- 在
application
启动代码里… - 创建
ContainerBuilder
对象 - 注册组件
- Build容器并且保存以备用
- 在程序执行阶段
- 从容器创建一个作用域
- 在作用域里获取组件的实例
应用程序构建
在我们的例子里,我们将定义一个类来输出当前的日期。当然,我们不希望和Console
绑定因为我们想在控制台不可用的情况依然可以测试这个类。
同样,输入日期的方法被定义成抽象的,这样的话如果我们想新增一个输出明天日期的方法就可以直接重载。
我们先定义一段代码:
using System;
namespace DemoApp
{
// 这个接口帮助我们从Console类解耦"输出"方法
// 我们不需要关心怎样输出,只要知道能输出即可
public interface IOutput
{
void Write(string content);
}
// 这里IOutput接口的实现完成向控制台的输出。
// 技术上讲,我们可以实现IOutput接口完成Debug或者Trace或者
// 其他的输出方式
public class ConsoleOutput : IOutput
{
public void Write(string content)
{
Console.WriteLine(content);
}
}
// 这个接口解耦实际输出日期的接口。
// 像IOutput一样,这个处理在后面的接口里抽象化
public interface IDateWriter
{
void WriteDate();
}
// ToadyWriter将上述两个接口进行组合
// 注意这里的构造函数参数是IOutput类型
// 这样这个writer的输出由IOutput的实现决定
// 更进一步说,他实现了WriteDate输出今天的日期
// 你可以再定义一个输出不同格式或者不同日期的方法
public class TodayWriter : IDateWriter
{
private IOutput _output;
public TodayWriter(IOutput output)
{
this._output = output;
}
public void WriteDate()
{
this._output.Write(DateTime.Today.ToShortDateString());
}
}
}
应用程序启动
在应用程序启动过程中,首先要创建一个ContainerBuilder
并且用它注册你的组件。组件是一个表达式, .NET类型或者其他的一段暴露一个或者多个服务的代码并且可以用在其他的依赖里。
简单来说,就像下面的例子所述,定义一个实现某个接口的.NET类型
public class SomeType : IService
{
}
你可以通过下面两种方法之一来定位这个类型
- 指定类型本身,
SomeType
- 指定接口,一个
IService
在这个例子里,这个组件是SomeType
,他暴露的服务是SomeType
和IService
.
在Autofac里,你应当用一个ContainerBuilder
来注册他们,如下:
// 创建你的builder
var builder = new ContainerBuilder();
// 通常你只关心这个接口的一个实现
builder.RegisterType<SomeType>().As<IService>();
// 当然,如果你想要全部的服务(不常用),可以这么写:
builder.RegisterType<SomeType>().AsSelf().As<IService>();
在我们的例子里,我们要注册所有的组件(类)并且获取他们的服务(接口),这样这些对象连接起来会更方便
我们还要保存这个容器,这样我们可以在后面用来解析这些类型
using System;
using Autofac;
namespace DemoApp
{
public class Program
{
private static IContainer Container { get; set; }
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<ConsoleOutput>().As<IOutput>();
builder.RegisterType<TodayWriter>().As<IDateWriter>();
Container = builder.Build();
// 我们将在这个方法里使用依赖注入,后面我们会定义它
WriteDate();
}
public static void WriteDate()
{
// 创建作用域,解析IDateWriter,使用,然后释放
using (var scope = Container.BeginLifetimeScope())
{
var writer = scope.Resolve<IDateWriter>();
writer.WriteDate();
}
}
}
}
当你运行你的程序时…
- WriteDate方法要求Autofac提供
IDateWriter
. - Autofac发现
IDateWriter
映射到TodayWriter
所以创建了一个TodayWriter
对象 - Autofac发现
TodayWriter
构造函数需要IOutput
- Autofac发现
IOutput
映射到ConsoleOutput
,所以创建一个新的ConsoleOutput
的实例 - Autofac使用
ConsoleOutput
实例完成TodayWriter
的创建 - Autofac返回一个完整的
TodayWriter
对象给”WriteDate”来消费
最后,如果你希望你的应用输出一个不同的日期,你可以实现另外一个IDateWriter
然后再app启动的时候改变一下注册过程。你不需要修改任何其他的类。耶,控制反转了!
注意:通常来说,服务定位大多都考虑了反面模式(参考) http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx。就是说,在你的代码里到处分散的手动创建作用域不是最佳的实现方式。使用Autofac整合库以后,你通常不需要做本例中的处理。相反的,对象很少在应用程序的”顶级”位置解析或者在手动解析。当然,怎么设计你的app是由你自己决定的。
更进一步
这个例子告诉你怎么使用Autofac,但是你还需要了解更多的内容
- 查看Autofac整合库列表来了解如何整合Autofac到你的应用程序里
- 学习注册组件的方法提高代码灵活性
- 学习Autofac配置选项更好的管理你的组件注册