Autofac之类型关联

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

public interface IPerson
{
    void Say();
}

public class Worker : IPerson
{
    public void Say()
    {
        Console.WriteLine("工人!");
    }
}

public class Student : IPerson
{
    public void Say()
    {
        Console.WriteLine("学生!");
    }
}

public class AutoFacManager
{
    IPerson person;

    public AutoFacManager(IPerson MyPerson)
    {
        person = MyPerson;
    }

    public void Say()
    {
        person.Say();
    }
}

使用AS进行关联函数

//IPerson类型的服务和Worker的组件链接起来,这个服务能够建立Worker类的实例
builder.RegisterType<Worker>().As<IPerson>();
using (var container = builder.Build())
{
    var obj = container.Resolve<IPerson>();
    obj.Say();
}

多关联学习

public interface IPerson
{
    void Say();
}
public interface IDuty
{
    void Write();
}

public class Worker : IPerson, IDuty
{
    public void Say()
    {
        Console.WriteLine("工人!");
    }

    public void Write()
    {
        Console.WriteLine("个人工做内容是搬砖!");
    }
}

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

builder.RegisterType<Worker>()
    .As<IPerson>()
    .As<IDuty>();
using (var container = builder.Build())
{
    var obj1 = container.Resolve<IPerson>();
    var obj2 = container.Resolve<IDuty>();
    obj1.Say();
    obj2.Write();
} 

自关联AsSelf

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

builder.RegisterType<Worker>().As<IPerson>();//这么写获取实例必须使用As类型进行Resolve 
builder.RegisterType<Worker>().As<IPerson>().AsSelf();//这么写可使用原类型进行Resolve 
using (var container = builder.Build())
{
    var obj1 = container.Resolve<Worker>();//builder.RegisterType<Worker>().As<IPerson>().As<Worker>();或者builder.RegisterType<Worker>().As<IPerson>().AsSelf();均可以
    var obj2 = container.Resolve<IPerson>();//必须builder.RegisterType<Worker>().As<IPerson>();          
    obj1.Say();
    obj2.Say();
}

批量关联AsImplementedInerfaces

以前说到能够经过多个As为一个类型关联多个接口,可是若是实现接口过多代码仍是不够简洁,经过AsImplementInterfaces方法,可让全部注册类型自动与实现的接口进行关联。固然,也正由于这点,在使用AsImplementInterfaces时须要注意,是否真的但愿与全部接口都进行关联设计

builder.RegisterType<Worker>().AsImplementedInterfaces();
using (var container = builder.Build())
{
    var obj1 = container.Resolve<IPerson>();
    var obj2 = container.Resolve<IDuty>();
    obj1.Say();
    obj2.Write();
}

类型关联注意点

一个接口/类型只能与一个类型进行关联,前面咱们看到了,能够将一个类型与多个接口进行关联,让多个接口Resolve结果都是同一个类型实例。须要注意的是,这个是不可逆的,也就是一个接口不能与多个类型进行关联,由于这样autofac不知道应该返回哪一个类型实例code

builder.RegisterType<Worker>().As<IPerson>();
builder.RegisterType<Student>().As<IPerson>();
using (var container = builder.Build())
{
    var obj = container.Resolve<IPerson>();
    obj.Say();
}

最后实际与I接口关联的类型是Student,Autofac中按注册顺序,后面注册的会覆盖前面注册的。若是想要阻止这种默认行为(相同接口/类型进行屡次类型关联,后面的关联覆盖前面的关联),能够在As方法调用用继续调用PreserveExistingDefaults方法,这样,若是以前该接口/类型已经进行关联注册,则这次关联无效component

关联类型与注册类型须要时继承/实现关系或为其自己

builder.RegisterType<X>().As<Y>();

当这样进行注册关联时,须要X继承或实现Y,再或者Y就是X类型,不然将在builder调用Build方法时抛出异常。blog

一、类型继承

类型是描述服务的基本方法

builder.RegisterType<Worker>().As<IPerson>();  //IPerson类型的服务和Worker的组件链接起来,这个服务能够建立Worker类的实例

二、名字

服务能够进一步按名字识别。使用这种方式时,用 Named()注册方法代替As()以指定名字

builder.RegisterType<Worker>().Named<IPerson>("worker");
builder.RegisterType<Student>().Named<IPerson>("student");
using (var container = builder.Build())
{
    var obj1 = container.ResolveNamed<IPerson>("worker");
    obj1.Say();
    var obj2 = container.ResolveNamed<IPerson>("student");
    obj2.Say();
}

三、键

有Name的方式很方便,可是值支持字符串,但有时候咱们可能须要经过其余类型做键。

例如,使用枚举做为key:

public enum State { Worker, Student }
builder.RegisterType<Worker>().Keyed<IPerson>(State.Worker);
builder.RegisterType<Student>().Keyed<IPerson>(State.Student);
using (var container = builder.Build())
{
    var obj1 = container.ResolveKeyed<IPerson>(State.Worker);
    obj1.Say();
    var obj2 = container.ResolveKeyed<IPerson>(State.Student);
    obj2.Say();
}

ResolveKeyd()会致使容器被当作 Service Locator使用,这是不被推荐的。应该使用IIndex type替代。

IIndex索引,须要using Autofac.Features.Indexed

Autofac.Features.Indexed.IIndex<K,V>是Autofac自动实现的一个关联类型。component可使用IIndex<K,V>做为参数的构造函数从基于键的服务中选择须要的实现

builder.RegisterType<Student>().Keyed<IPerson>(State.Student);
using (IContainer container = builder.Build())
{
    IIndex<State, IPerson> IIndex = container.Resolve<IIndex<State, IPerson>>();
    IPerson p = IIndex[State.Student];
    p.Say();
}

IIndex中第一个泛型参数要跟注册时一致,在例子中是State枚举。其余两种注册方法没有这样的索引查找功能,这也是为何设计者推荐Keyed注册的缘由之一

相关文章
相关标签/搜索