Autofac是.NET领域最为流行的IOC框架之一,非常容易上手。下面介绍一下具体的使用方法。
1. 定义测试接口及其实现类
我们需要新建一个控制台程序。
再定义三个我们要在后面用到的接口
/// <summary>
/// 玩家
/// </summary>
public interface IPlayer
{
string Name { get; }
void Attack();
}
/// <summary>
/// 敌人
/// </summary>
public interface IEnemy
{
string Name { get; }
}
/// <summary>
/// 武器
/// </summary>
public interface IWeapon
{
string Name { get; }
}
大致的关系就是玩家拿起武器攻击敌人。
IPlayer有Knight和Archmage这两个实现类。
public class Knight : IPlayer
{
IWeapon _weapon;
IEnemy _enemy;
public Knight(IWeapon weapon, IEnemy enemy)
{
_weapon = weapon;
_enemy = enemy;
}
public string Name { get { return "骑士"; } }
public void Attack()
{
Console.WriteLine("{0}拔出了{1},奋力攻击{2}", this.Name, _weapon.Name, _enemy.Name);
}
}
public class Archmage: IPlayer
{
IWeapon _weapon;
IEnemy _enemy;
public Archmage(IWeapon weapon, IEnemy enemy)
{
_weapon = weapon;
_enemy = enemy;
}
public string Name { get { return "大法师"; } }
public void Attack()
{
Console.WriteLine("{0}开始吟唱{1},{2}被{1}炸飞", this.Name, _weapon.Name, _enemy.Name);
}
}
细心的读者也许注意到IPlayer还依赖两个接口,其实现类如下:
public class Fireball : IWeapon
{
public string Name { get { return "火球术"; } }
}
public class Sword : IWeapon
{
public string Name { get { return "剑"; } }
}
现在我们的武器有了剑和火球术,接下来我们来增加两个敌人:
public class Orca : IEnemy
{
public string Name { get { return "兽人"; } }
}
public class Goblin : IEnemy
{
public string Name { get { return "哥布林"; } }
}
OK,测试对象们都已经就绪,让我们开始游戏吧。
如果我们不使用控制反转,那么测试代码将会是以下这样:
var weapon = new Fireball();
var enemy = new Orca();
var player = new Archmage(weapon, enemy);
player.Attack();
运行的结果是:
很简单的代码,运行也正常,但是如果我们想使用Knight去攻击Orca,那就需要去修改代码,这样显得有点low,如果我们使用控制反转的话,一切就都简单了,所以我们决定要将依赖关系交给某个容器去管理,也就是交给Autofac。
2. 安装Autofac
Autofac可以使用NuGet安装。
3. 注册和配置
新建一个名叫AutofacExt的静态类,然后在类中实现一个初始化容器的方法,我们把所有要用到的类型都注册进去。
public static void InitAutofac()
{
static ContainerBuilder _builder;
/// <summary>
/// 初始化
/// </summary>
public static void InitAutofac()
{
_builder = new ContainerBuilder();
//武器
_builder.RegisterType<Fireball>();
_builder.RegisterType<Sword>();
//玩家
_builder.RegisterType<Archmage>();
_builder.RegisterType<Knight>();
//敌人
_builder.RegisterType<Orca>();
_builder.RegisterType<Goblin>();
//读取配置
_builder.RegisterModule(new ConfigurationSettingsReader("autofac"));
}
}
等等,读取配置?什么配置?
对象是注册到容器中了,可是我该使用那些接口哪个实例呢?配置就是用来做这个的,如下:
<configuration>
<configSections>
<section name="autofac" type="Autofac.Configuration.SectionHandler, Autofac.Configuration"/>
</configSections>
<autofac defaultAssembly="AutoFacDemo">
<components>
<component type="AutoFacDemo.Fireball" service="AutoFacDemo.IWeapon" />
<component type="AutoFacDemo.Knight" service="AutoFacDemo.IPlayer" />
<component type="AutoFacDemo.Orca" service="AutoFacDemo.IEnemy" />
</components>
</autofac>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>
配置信息一目了然。
4. 获取配置的对象
InitAutofac类还不完善,只有初始化,却没有从容器中获取对象的方法怎么行。
所以我们再在InitAutofac类中增加以下代码:
static IContainer _container;
static IContainer Container {
get
{
if (_container == null)
_container = _builder.Build();
return _container;
}
/// <summary>
/// 从容器中获取对象
/// </summary>
/// <typeparam name="T"></typeparam>
public static T GetFromFac<T>()
{
T t = Container.Resolve<T>();
return t;
}
这里值得注意的是,ContainerBuilder这个容器对象只能运行一次Build方法。
5. 修改测试代码
AutofacExt.InitAutofac();
IPlayer player = AutofacExt.GetFromFac<IPlayer>();
player.Attack();
如此简洁的代码,妈妈再也不用担心我的构造函数和依赖关系了。
运行的结果是:
骑士拔出了火球术?是不是哪里出错了?
原来是我们依赖的对象出了点问题,不过没什么好担心的,只需要修改一下配置文件就搞定了。
修改配置之后再运行一次:
6. 结语
以上只是一个简单的Demo,可能会与生产环境有所不同,比如要在MVC环境中使用Autofac,那么我们的InitAutofac类需要修改一下。
- 在InitAutofac方法中增加以下代码:
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
- 将GetFromFac方法改为:
public static T GetFromFac<T>()
{
return (T)DependencyResolver.Current.GetService(typeof(T));
}