如何使用Autofac实现控制反转

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();

运行的结果是:

运行结果1.png

很简单的代码,运行也正常,但是如果我们想使用Knight去攻击Orca,那就需要去修改代码,这样显得有点low,如果我们使用控制反转的话,一切就都简单了,所以我们决定要将依赖关系交给某个容器去管理,也就是交给Autofac。


2. 安装Autofac

Autofac可以使用NuGet安装。

NuGet.png

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();

如此简洁的代码,妈妈再也不用担心我的构造函数和依赖关系了。
运行的结果是:

运行结果2.png

骑士拔出了火球术?是不是哪里出错了?
原来是我们依赖的对象出了点问题,不过没什么好担心的,只需要修改一下配置文件就搞定了。

错误

修改配置之后再运行一次:

运行结果3.png

6. 结语

以上只是一个简单的Demo,可能会与生产环境有所不同,比如要在MVC环境中使用Autofac,那么我们的InitAutofac类需要修改一下。

  1. 在InitAutofac方法中增加以下代码:
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
  1. 将GetFromFac方法改为:
public static T GetFromFac<T>()
{
            return (T)DependencyResolver.Current.GetService(typeof(T));
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,629评论 18 139
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,209评论 11 349
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,773评论 6 342
  • 身在职场,有很多事情身不由己,有很多问题不管我们怎样做都无法找到最佳的答案。很多问题让我们束手无策,当你遇到下面的...
    职场蜜蜜阅读 763评论 0 0