autofac
Autofac是一套高效的依赖注入框架。javascript
Autofac官方网站:http://autofac.org/html
Autofac在Github上的开源项目:https://github.com/autofac/Autofacjava
Autofac安装:经过VS的Nuget能够很方便的获取。git
类型关联(服务暴露)
关于“类型关联(服务暴露)”这个名字,是源于官网上的exposes一词,有点词穷,但愿你们在看完博客后可以提供更加贴切的描述名称。github
前面的autofac系列文章一直有提到直接注册类型并非autofac已经依赖注入的主要使用方式,最佳的依赖注入与autofac的使用方式,都是要结合面向接口(抽象)编程的概念的。咱们推崇的是依赖于抽象而不是具体,关于这点,我在上一篇博文最后的总结中有简单的说明。编程
了解autofac的朋友在看前面的博文的时候,可能会以为很别扭,由于没有使用As<>。可是博主以为依赖注入并非必定要与接口或抽象类关联在一块儿才能算依赖注入,博主是想将依赖注入与面向抽象编程稍稍分离开来,在你们理解依赖注入的概念后再来与面向抽象编程概念相结合,这样对于初学者可能更方便吸取。后面的博客实例代码也会根据实际状况来决定是否使用类型关联(服务暴露),一切从简了。数组
As关联
关于类型关联(服务暴露)的内容其实并很少,咱们在进行手动关联时,基本都是使用As进行关联的。咱们先来看看一个实例吧:框架
class Program { static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterType<Class1>().As<IInterface>(); var container = builder.Build(); IInterface inter = container.Resolve<IInterface>(); Console.WriteLine(inter.Id); Console.Write("Press any key to continue..."); Console.ReadKey(); } }interface IInterface { Guid Id { get; } } class Class1 : IInterface { private Guid _id; public Guid Id { get { return _id; } } }从代码中能够看到,咱们直接在类型注册后加了一句As<…>(),而后咱们在使用Resolve时,咱们也是用的As的类型。网站
让咱们回顾一下以前的用法,以前是直接RegisterType,最后注册的类型是Class1,Resolve时,也是直接用Class1。而如今注册的虽然仍是Class1,可是获取时倒是用IInterface,而且最后获取到的实例类型是Class1。这样看有点绕,代码层面上是这样的,但咱们也能够理解为注册了IInterface,可是为IInterface指定了实现。这样作的好处在于,咱们若是但愿更改IInterface的实现,只须要修改注册的代码,而不须要修改获取处以及后续使用IInterface实例的代码。ui
As还有两种重载,一种是Type可变数组,另外一种是Service可变数组。第二种方式咱们通常不用,autofac底层使用,推荐篇不进行说明。
这里使用RegisterType进行注册的,一样,其余注册方式也可使用As进行类型关联。
多关联
一个类可能实现多个接口,若是咱们但愿Resolve多个接口时获取到的都是那个类型,应该怎么作呢?最容易想到的方式就是直接再注册As一遍就行了。嗯,这样确实是能够的,可是你们是否记得IEnumerable和IQueryable那种链式编程的方式不?autofac一样有这样简便的方式,若是但愿多个接口或类型都与同一个类型进行关联,咱们能够直接再表达式后面继续As:builder.RegisterType<C1>().As<I1>().As<I2>().As<I3>,如此,Resolve<I1>、Resolve<I2>、Resolve<I3>获取到的都是C1类型实例。
自关联AsSelf
As使用注意
不使用As时,RegisterType注册的是什么类型,Resolve就使用什么类型进行获取,可是在使用As后,就只能使用As的类型进行Resolve。好比前面的例子中,只可以Resolve<IInterface>,而不能Resolve<Class1>,不然将抛出异常。
可是若是还想在Resolve<Class1>时可以获取到Class1而不抛出异常,应该怎么办呢?在不知道AsSelf方法的状况下,能够在注册时直接As<Class1>,这样就能够了。另外一种方式就是AsSelf了:
// 这两句代码效果相同 builder.RegisterType<Class1>().As<IInterface>().As<Class1>(); builder.RegisterType<Class1>().As<IInterface>().AsSelf();相对而言,不论什么类型,最后只需AsSelf就好了,这样相对方便,可是具体仍是要看我的习惯了。
批量关联AsImplementedInerfaces
根据这个方法的名称,咱们大概可以猜出它的做用了,AsImplementedInterfaces也就是直接与类型实现的接口进行类型关联。好比有如下类型定义:
interface I1 { } interface I2 { } interface I3 { } interface I4 { } interface I5 { } interface I6 { } interface I7 { } class C1 : I1, I2, I3, I4, I5, I6, I7 { }一个类型实现了7个接口,而后咱们但愿Resolve这七个中任何一个接口,都能获取到C1实例,按照咱们第一节中说的多关联,代码能够简写为:
builder.RegisterType<C1>() .As<I1>().As<I2>() .As<I3>().As<I4>() .As<I5>().As<I6>() .As<I7>();虽然这个代码相对RegisterType屡次再屡次As简洁了不少,可是仍是不够简洁,然而在有AsImplementInterfaces方法后,就可以很是简单:
builder.RegisterType<C1>().AsImplementedInterfaces();在程序集注册这种方式中,AsImplementInterfaces更能显示出威力,程序集注册这种方式中,都是批量注册类型的,批量注册的这些类型,它们可能都实现了不一样的接口,这样咱们没办法为它们一一关联接口,可是经过AsImplementInterfaces方法,可让全部注册类型自动与实现的接口进行关联。固然,也正由于这点,在使用AsImplementInterfaces时须要注意,是否真的但愿与全部接口都进行关联。
一个接口/类型只能与一个类型进行关联
在前面咱们看到了,能够将一个类型与多个接口进行关联,让多个接口Resolve结果都是同一个类型实例。须要注意的是,这个是不可逆的,也就是一个接口不能与多个类型进行关联,由于这样autofac不知道应该返回哪一个类型实例。代码实例:
builder.RegisterType<C1>().As<I>(); // class C1 : I builder.RegisterType<C2>().As<I>(); // class C2 : Iinterface I { } class C1 : I { } class C2 : I { }按上面的代码,最后实际与I接口关联的类型是C2,autofac中按注册顺序,后面注册的会覆盖前面注册的。若是想要阻止这种默认行为(相同接口/类型进行屡次类型关联,后面的关联覆盖前面的关联),能够在As方法调用用继续调用PreserveExistingDefaults方法,这样,若是以前该接口/类型已经进行关联注册,则这次关联无效:
builder.RegisterType<C1>().As<I>(); // class C1 : I builder.RegisterType<C2>().As<I>().PreserveExistingDefaults(); // class C2 : I上面的代码,经过Resolve<I>()获取到时C1类型实例。
一个接口关联多个类型注意
这里说的一个接口不能关联多个类型,是针对这种经常使用的注册及关联。其实能够经过Named<>、Meta<>这种方式进行多关联,关于此类话题后续博文将会谈到。
关联类型与注册类型须要时继承/实现关系或为其自己
builder.RegisterType<X>().As<Y>();当这样进行注册关联时,须要X继承或实现Y,再或者Y就是X类型,不然将在builder调用Build方法时抛出异常。
看完本篇博文,autofac最基本/经常使用的功能就完结了。可是如今只是最基本的功能,推荐篇并无结束,还有一些内容,我认为仍是须要掌握的,但愿你们继续关注,谢谢!