第四节 注册组件

组件,是数据与方法的封装。也就是对象,所以除去标题外,其他地方用对象代替组件。

使用AutoFac,分为两步,注册对象与创建对象,即放进来与拿出去。

注册对象,分为三步

  1. 创建容器
    var builder = new ContainerBuilder();
  2. 注册对象
    builder.xxxxxx这一节,探究AutoFac提供注册对象的各种方式
  3. 容器闭合
    var container = builder.Build();

单独注册

按类型注册

公开注册类型

//按类型注册,公开该类型
builder.RegisterType();

//使用类型解析
var person = container.Resolve();

公开接口

//按类型注册,使用As公开接口
builder.RegisterType().As();

//使用接口解析
var person = container.Resolve();

公开注册类型与接口

//按类型注册,使用AsSelf公开类型,用As公开接口
builder.RegisterType().AsSelf().As();

//可以使用类型/接口解析
var person1 = container.Resolve();
var person2 = container.Resolve();

公开多个接口

//按类型注册,用As公开接口
builder.RegisterType().As().As();

//可以使用多种接口解析
var person = container.Resolve();
var people= container.Resolve();

按实例注册

注册普通对象

builder.RegisterInstance(new Student());

var student = new Student();
builder.RegisterInstance(student);

builder.Register(c => new Student());

按实例注册后,实例的生命周期由AutoFac处理,如果想要自己来处理

builder.RegisterInstance(new Student()).ExternallyOwned();

注册单例对象,同样,单例的对象也是实例对象的一种

builder.RegisterInstance(Worker.CreateInstance());
builder.RegisterInstance(Worker.CreateInstance()).ExternallyOwned();

批量注册

按程序集注册

当前程序集中,非静态的公开类型被批量注册

var dataAccess = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(dataAccess);

var worker= container.Resolve();
var manager = container.Resolve();

引用的相关程序集,也可以批量注册非静态的公开类型

var assembly = typeof(User).Assembly; 
builder.RegisterAssemblyTypes(assembly);

//User与Fire在引用的其他工程中
var user = container.Resolve();
var fire = container.Resolve();

批量注册并批量公开相应的接口

var assembly = typeof(User).Assembly;

//AsImplementedInterfaces很方便的将注册类型公开为各自继承的接口
builder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();

//User继承IEntities,Fire继承IModel
var user = container.Resolve();
var fire = container.Resolve();

根据程序集的属性,使用Where过滤要注册的类型

var dataAccess = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(dataAccess).Where(t => t.Name.EndsWith("er"));

//student创建失败,因为对象的类型名称不少以er结尾
var worker= container.Resolve();
var manager = container.Resolve();
var student = container.Resolve();

根据程序集的属性,使用Except过滤要注册的类型

var dataAccess = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(dataAccess).Except();

//worker创建失败,因为没有注册
var manager = container.Resolve();
var student = container.Resolve();
var worker= container.Resolve();

按模块注册

var builder = new ContainerBuilder();
builder.RegisterModule();
//1.调用UserModule类型中的Load方法
var container = builder.Build();

namespace Entities
{
    //Module是AutoFac提供的实现IModule的类型
    public class UserModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            //2.注册User等类型
            builder.RegisterType();
            builder.RegisterType();
        }
    }
}

//3.创建User对象
User user = container.Resolve();

程序集中的模块

//获取UserModule所在程序集
var assembly = typeof(UserModule).Assembly;
var builder = new ContainerBuilder();
builder.RegisterAssemblyModules(assembly);
//调用UserModule所在程序集中所有实现IModule的类型的Load
var container = builder.Build();

默认注册

注册顺序

多个组件公开相同的服务,AutoFac将使用最后一个注册的组件

builder.RegisterType<Person>().AS<IPerson>();
builder.RegisterType<Student>().As<IPerson>();
//解析IPerson得到的是Student对象

使用PreserveExistingDefaults选择默认注册

builder.RegisterType().AS().PreserveExistingDefaults();
builder.RegisterType().As();
//解析IPerson得到的是Person对象

解析构造

容器在解析时,默认寻找到参数最多的构造函数

//Person类型重载3个构造
public Person(){}
public Person(Book book){}
public Person(Book book, Bag bag){}

//创建Person对象时,执行的构造根据注册情况而定
var person = container.Resolve();

情景1

builder.RegisterType<Bag>();
builder.RegisterType<Book>();
builder.RegisterType<Person>();
public Person(Book book, Bag bag){}

情景2

builder.RegisterType<Book>();
builder.RegisterType<Person>();
public Person(Book book){}

情景3

设置执行仅有Book类型参数的构造

builder.RegisterType().UsingConstructor(typeof(Book));

设置执行没有参数的构造

builder.RegisterType().UsingConstructor();

构造参数

internal class Worker : IPerson
{
    public Worker(string name)
    {
        Console.WriteLine(name);
    }
}

在注册时确定参数

var builder = new ContainerBuilder();
// 方式1 按名称匹配
builder.RegisterType().As().WithParameter("name", "eden");

//方式2 按类型匹配
builder.RegisterType().As().WithParameter(new TypedParameter(typeof(string), "eden"));

//方式3 Lambda
builder.RegisterType().As().WithParameter(
new ResolvedParameter((pi, ctx) => pi.ParameterType == typeof(string) && pi.Name == "name", (pi, ctx) => "pp"));

var container = builder.Build();

在解析时确定参数

var builder = new ContainerBuilder();
builder.Register((c, p) =>new Worker(p.Named("name"))).As<IPerson>();
var container = builder.Build();

var obj = container.Resolve<IPerson>(new NamedParameter("name", "pp"));

初始化属性

用Lambda可以初始化属性,c在这里代表注册的上下文IComponentContext

builder.Register(c=> new Student(){ Name = "eden", BookObj = new Book()});

c.ResolveOptional()意味着从注册的中寻找Book对象反射创建来填充BookObj属性

builder.RegisterType();
builder.Register(c=> new Student(){ Name = "eden", BookObj = c.ResolveOptional()});

选择注册

参数化

var builder = new ContainerBuilder();

builder.Register(
  (c, p) =>
  {
     var id = p.Named("id");
     if (1 == id)
     {
         return new Student();
     }
     else  //细节
     {
         return new Worker();
     }
   });

var container = builder.Build();

var obj = container.Resolve(new NamedParameter("id", 1));

在解析时,传入一个临时的参数key-value(id = 1),容器根据参数进行逻辑处理,决定选择哪个对象实例化创建

细节:这里必须return一个对象,由else改为else if无法通过编译


条件化
    如果没有注册A才注册B

var builder = new ContainerBuilder();
//②在这里注册了Worker类型并暴露为IPerson类型
builder.RegisterType().As();
//③如果没有暴露的IPerson类型,注册Student类型
builder.RegisterType().As().IfNotRegistered(typeof(IPerson));
var container = builder.Build();

//解析为Worker类型
var obj = container.Resolve();
var builder = new ContainerBuilder();
//②如果没有暴露的IPerson类型,注册Student类型
builder.RegisterType().As().IfNotRegistered(typeof(IPerson));
var container = builder.Build();

//解析为Student类型
var obj = container.Resolve();

    如果注册了A才注册B

var builder = new ContainerBuilder();
//② 注册了Worker类型,并暴露为IPerson类型
builder.RegisterType().As();
//③ 如果有暴露的IPerson类型,才注册Manager类型,并暴露为IManager类型
builder.RegisterType().As().OnlyIf(reg=>reg.IsRegistered(new TypedService(typeof(IPerson))));
var container = builder.Build();

var obj= container.Resolve();
var builder = new ContainerBuilder();
//② 如果有暴露的IPerson类型,才注册Manager类型,并暴露为IManager类型
builder.RegisterType().As().OnlyIf(reg=>reg.IsRegistered(new TypedService(typeof(IPerson))));
var container = builder.Build();

//编译通过,运行出错
var obj= container.Resolve();

第四节 注册组件_第1张图片

泛型注册

internal interface IRepository
{
    void Add(T item);
}
internal class EntityFrameworkRepository : IRepository
{
    public void Add(T item)
    {
        Console.WriteLine(item);
    }
}
var builder = new ContainerBuilder();       
builder.RegisterGeneric(typeof(EntityFrameworkRepository<>)).As(typeof(IRepository<>));
var container = builder.Build();
var workerRepository = container.Resolve>();
workerRepository.Add(new Worker());

var studentRepository= container.Resolve>();
studentRepository.Add(new Student());

internal class Worker : People, IPerson
{
    public Student Student { get; set; }
    public string Name { get; set; }

    public Worker(string name)
    {
        Console.WriteLine(name);
    }
}

Lambda + 对象初始化器

var builder = new ContainerBuilder();
builder.Register(c=> new Worker {Name = "eden"});
var container = builder.Build();

var obj = container.Resolve();

名称匹配

var builder = new ContainerBuilder();
builder.RegisterType().WithProperty("Name", "eden");
var container = builder.Build();

var obj = container.Resolve();

反射组件

var builder = new ContainerBuilder();
//student使用已注册
builder.RegisterType();
//PropertiesAutowired将在解析创建Worker对象时自动创建属性的Student对象
builder.RegisterType().PropertiesAutowired();
var container = builder.Build();

//obj.Student != null
var obj = container.Resolve();

注入循环依赖

public class ClassA
{
    private readonly ClassB _b;

    public ClassA(ClassB b)
    {
        _b = b;
    }
}

public class ClassB
{
    public ClassA ClassA { get; set; }
}

ClassA与ClassB已经造成循环依赖

var builder = new ContainerBuilder();
builder.Register(c => new ClassA(new ClassB()));
builder.Register(c => new ClassB()).OnActivated(e => e.Instance.ClassA = e.Context.Resolve());
var container = builder.Build();

var obj = container.Resolve();

internal class Worker : People, IPerson
{
    private Student _student;
    private string _name;

    public void SetName(string name)
    {
        _name = name;
    }

    public void SetStudent(Student student)
    {
        _student = student;
    }
}

方式1

var name = "eden";
var builder = new ContainerBuilder();
 builder.Register(c =>
 {
     var worker = new Worker();
     worker.SetName(name);
     return worker;
 });
 var container = builder.Build();

 var obj = container.Resolve();

方式2

var name = "eden";
var builder = new ContainerBuilder();
builder.RegisterType();
builder.RegisterType()
    .OnActivating(e =>
    {
        var stu = e.Context.Resolve();
        e.Instance.SetStudent(stu);
    });
var container = builder.Build();

var obj = container.Resolve();

后记
        花费了将近2个星期内的空余时间,看官网中组件注册这一章,按照自己的逻辑归纳出这篇博客。使用程序集注册+自动公开接口的方式,将Services模块注册,一行代码干掉了140行。
第四节 注册组件_第2张图片

你可能感兴趣的:(Major:AutoFac,AutoFac)