第四节 注册组件

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

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

注册对象,分为三步

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

单独注册

按类型注册

公开注册类型

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

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

公开接口

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

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

公开注册类型与接口

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

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

公开多个接口

//按类型注册,用As公开接口
builder.RegisterType<Person>().As<IPerson>().As<IPeople>();

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

按实例注册

注册普通对象

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<Worker>();
var manager = container.Resolve<Manager>();

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

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

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

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

var assembly = typeof(User).Assembly;

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

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

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

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

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

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

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

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

按模块注册

var builder = new ContainerBuilder();
builder.RegisterModule<UserModule>();
//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<User>();
            builder.RegisterType<Student>();
        }
    }
}

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

程序集中的模块

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

默认注册

注册顺序

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

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

使用PreserveExistingDefaults选择默认注册

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

解析构造

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

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

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

情景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<Person>().UsingConstructor(typeof(Book));

设置执行没有参数的构造

builder.RegisterType<Person>().UsingConstructor();

构造参数

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

在注册时确定参数

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

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

//方式3 Lambda
builder.RegisterType<Worker>().As<IPerson>().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<string>("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>()意味着从注册的中寻找Book对象反射创建来填充BookObj属性

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

选择注册

参数化

var builder = new ContainerBuilder();

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

var container = builder.Build();

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

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

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


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

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

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

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

    如果注册了A才注册B

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

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

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

这里写图片描述

泛型注册

internal interface IRepository<T>
{
    void Add(T item);
}
internal class EntityFrameworkRepository<T> : IRepository<T>
{
    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<IRepository<Worker>>();
workerRepository.Add(new Worker());

var studentRepository= container.Resolve<IRepository<Student>>();
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<Worker>();

名称匹配

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

var obj = container.Resolve<Worker>();

反射组件

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

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

注入循环依赖

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<ClassA>());
var container = builder.Build();

var obj = container.Resolve<ClassB>();

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<Worker>();

方式2

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

var obj = container.Resolve<Worker>();

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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值