我们在进行手动关联时,基本都是使用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实例的代码。
As还有两种重载,一种是Type可变数组,另一种是Service可变数组。第二种方式我们一般不用,autofac底层使用,推荐篇不进行说明。
这里使用RegisterType进行注册的,同样,其他注册方式也可以使用As进行类型关联。
多关联 一个类可能实现多个接口,如果我们希望Resolve多个接口时获取到的都是那个类型,应该怎么做呢?如果希望多个接口或类型都与同一个类型进行关联,我们可以直接再表达式后面继续As:builder.RegisterType<C1>().As<I1>().As<I2>().As<I3>,如此,Resolve<I1>、Resolve<I2>、Resolve<I3>获取到的都是C1类型实例。
// 这两句代码效果相同 builder.RegisterType<Class1>().As<IInterface>().As<Class1>(); builder.RegisterType<Class1>().As<IInterface>().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 : 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<>这种方式进行多关联
b.builder.RegisterType<X>().As<Y>();
当这样进行注册关联时,需要X继承或实现Y,再或者Y就是X类型,否则将在builder调用Build方法时抛出异常。