Autofac入门之类型关联服务暴露

前面的学习一直使用的是直接注册类型并不是Autofac已经依赖注入的主要使用方式,最佳的依赖注入与Autofac的使用方式,都是要结合面向接口(抽象)编程的概念的。推崇的是依赖于抽象而不是具体

interface IInterface
{
    void Add();
}

public class ClassA : IInterface
{
    public void Add()
    {
        Console.WriteLine("ClassA");
    }
}
public class ClassB : IInterface
{
    public void Add()
    {
        Console.WriteLine("ClassB");
    }
}

使用AS进行关联

var builder = new ContainerBuilder();
//IInterface类型的服务和ClassB的组件连接起来,这个服务可以创建ClassB类的实例
builder.RegisterType<ClassA>().As<IInterface>();
var container = builder.Build();
Iinterface obj = container.Resolve<IInterface>();

从代码中可以看到,我们直接在类型注册后加了一句As<…>(),然后我们在使用Resolve时,我们也是用的As的类型。让我们回顾一下之前的用法,之前是直接RegisterType,最后注册的类型是ClassA,Resolve时,也是直接用ClassA。而现在注册的虽然还是ClassA,但是获取时却是用IInterface,并且最后获取到的实例类型是ClassA。这样看有点绕,代码层面上是这样的,但我们也可以理解为注册了IInterface,但是为IInterface指定了实现。这样做的好处在于,我们如果希望更改IInterface的实现,只需要修改注册的代码,而不需要修改获取处以及后续使用IInterface实例的代码。

多关联

interface IInterface1
{
    void Add();
}
interface IInterface2
{
    void Add();
}

public class ClassA : IInterface1, IInterface2
{
    public void Add()
    {
        Console.WriteLine("ClassA");
    }
}
public class ClassB : IInterface1, IInterface2
{
    public void Add()
    {
        Console.WriteLine("ClassB");
    }
}

一个类可能实现多个接口,如果我们希望Resolve多个接口时获取到的都是那个类型,应该怎么做呢?最容易想到的方式就是直接再注册As一遍就好了。Autofac提供了类似IEnumerable和IQueryable链式编程的方式,如果希望多个接口或类型都与同一个类型进行关联,我们可以直接在表达式后面继续As

builder.RegisterType<ClassA>()
    .As<IInterface1>()
    .As<IInterface2>();

自关联AsSelf

 不使用As时,RegisterType注册的是什么类型,Resolve就使用什么类型进行获取,但是在使用As后,就只能使用As的类型进行Resolve;但是如果还想在Resolve<ClassA>时能够获取到ClassA而不抛出异常,应该怎么办呢?在不知道AsSelf方法的情况下,可以在注册时直接As<ClassA>,这样就可以了。另一种方式就是AsSelf

builder.RegisterType<ClassA>().As<IInterface1>().As<ClassA>();
builder.RegisterType<ClassA>().As<IInterface1>().AsSelf();

批量关联AsImplementedInerfaces

之前说到可以通过多个As为一个类型关联多个接口,但是如果实现接口过多代码还是不够简洁,通过AsImplementInterfaces方法,可以让所有注册类型自动与实现的接口进行关联。当然,也正因为这点,在使用AsImplementInterfaces时需要注意,是否真的希望与所有接口都进行关联

类型关联注意点

一个接口/类型只能与一个类型进行关联

在前面我们看到了,可以将一个类型与多个接口进行关联,让多个接口Resolve结果都是同一个类型实例。需要注意的是,这个是不可逆的,也就是一个接口不能与多个类型进行关联,因为这样autofac不知道应该返回哪个类型实例。代码实例:

builder.RegisterType<C1>().As<I>(); // class C1 : I
builder.RegisterType<C2>().As<I>(); // class C2 : I
interface 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方法时抛出异常。

猜你喜欢

转载自www.cnblogs.com/GnailGnepGnaw/p/10753626.html