从容器中的可用服务中选择一个构造函数来创造对象,这个过程叫做自动装配。这个过程是通过反射实现的

默认

思考这么一个问题,如果注册类型中存在多个构造函数,那么Autofac会选择哪一个来创建类型的实例

答案是"尽可能最多参数"

class ConstructorClass
{private Class1 _clas1;private Class2 _clas2;private Class3 _clas3 = null;public ConstructorClass(){_clas1 = null; _clas2 = new Class2 { Id = -1 };}public ConstructorClass(Class1 clas1, Class2 clas2){_clas1 = clas1; _clas2 = clas2;}public ConstructorClass(Class2 clas2, Class3 clas3){_clas2 = clas2; _clas3 = clas3;}public ConstructorClass(Class2 clas2, Class3 clas3, Guid guid){_clas1 = new Class1 { Id = guid }; _clas2 = clas2; _clas3 = clas3;}public ConstructorClass(Class1 clas1, Class2 clas2, Class3 clas3){_clas1 = clas1; _clas2 = clas2; _clas3 = clas3;}public override string ToString(){return string.Format("{{Class1.Id: {0}, Class2.Id: {1}, Class3: {2}}}",_clas1 == null ? "null" : _clas1.Id.ToString(),_clas2 == null ? "null" : _clas2.Id.ToString(),_clas3 == null ? "null" : "not null");}
}class Class1
{public Guid Id { get; set; }
}class Class2
{public int Id { get; set; }
}class Class3
{}static void Main(string[] args)

static void Main(string[] args)
{//注册容器var builder = new ContainerBuilder();//向容器中注册类型builder.RegisterType<ConstructorClass>();builder.RegisterType<Class2>();builder.RegisterType<Class3>();using (var container = builder.Build()){#region Resolve对象构造方法选择原则(当我们注册的类型拥有多个构造方法,那么在Resolve时,将会以尽可能最多参数构造方法为准)var obj = container.Resolve<ConstructorClass>();Console.WriteLine(obj);#endregion
    }Console.ReadKey();
}

该实例显示,选择的是第三个构造函数,参数为(Class2 clas2, Class3 clas3),

按照字面上里说明”最多参数“,那么理应执行的是最后一个构造方法或倒数第二个构造方法,但是为什么却是第三个,这也就是为什么我要加“尽可能”三字了。

先抛开为什么执行的第三个构造方法,我们还是会有疑问”如果执行的是第三个构造方法,那么Class2和Class3参数分别赋的是什么值?值又是从哪儿来?“,这里就涉及到了后面会讲到的构造注入。我们可以看到,在进行类型注册时,我们是对Class2和Class3进行了注册的,而ConstructorClass又是通过Autofac进行获取的,所以Class2和Class3参数的值是由Autofac进行初始化赋值的,Class2和Class3没有自定义构造方法,所以调用的是默认的空构造方法。

在知道Class2和Class3参数的初始化与赋值缘由后,我们再来看看之前的那个问题,为什么会执行第三个构造方法,其实现在就好明白了,因为最后两个的构造方法,一个需要额外的Guid类型参数,另一个需要Class1类型参数,而这两个类型又没有经过注册,如果调用这两个构造方法,那么Auotofac将不知道应该赋何值给这两个参数,所以Autofac最终选择了第三个构造方法。

此时我把第三个构造函数注释掉之后,会调用第一个构造函数,按照"尽可能最多参数"原则,此时不应该调用第二个吗?答案是,Autofac会在已注册的类型中寻找,虽然Class2类型被注册,第二个构造函数Class1类型参数Autofac不知道如何赋值,所以选择了默认的构造函数,如果在容器中注册类型Class1取消掉类型Class3的注册,此时就会调用第二个构造函数.(Autofac寻找构造函数的规则是在已注册的类型中寻找参数完全匹配的构造函数)

UsingConstructor:指定使用某个构造函数

通过上面的例子我们知道Autofac创建类型实例时会默认从容器中选择匹配参数最多的构造函数,此时在容器中将Class1、Class2、Class3类型都注册,此时默认情况会使用最后一个构造函数,如果如果想要选择一个不同的构造函数,就需要在注册的时候就指定它,此时指定使用参数为(Class1 clas1, Class2 clas2)的构造函数

builder.RegisterType<Class1>();
builder.RegisterType<Class2>();
builder.RegisterType<Class3>();

builder.RegisterType<ConstructorClass>().UsingConstructor(typeof(Class1), typeof(Class2));

额外的构造函数参数

有两种方式可以添加额外的构造函数参数,在注册的时候和在检索的时候。在使用自动装配实例的时候这两种都会用到。

注册时添加参数

使用WithParameters()方法在每一次创建对象的时候将组件和参数关联起来。

builder.RegisterType<ConstructorClass>().WithParameter("guid", Guid.NewGuid());
//builder.RegisterType<Class1>();//将Class1注册因为在尽可能最多的原则上,出现了两个最多参数的构造方法,Autofac不知道应该选择哪个进行执行
builder.RegisterType<Class2>();
builder.RegisterType<Class3>();

在检索阶段添加参数
在Resolve()的时候提供的参数会覆盖所有名字相同的参数,在注册阶段提供的参数会覆盖容器中所有可能的服务。

var obj = container.Resolve<ConstructorClass>(new NamedParameter("guid", Guid.NewGuid()));

自动装配

在需要的时候,依然可以创建指定的构造函数创建指定的类。

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

Resolve的方法签名为:Resolve<T>(this IComponmentContext context, params Parameter[] parameters)

第一个参数也就是我们使用的container,我们主要关注第二个参数——一个可变的Parameter数组,Parameter是一个抽象类,其中NamedParameter为Parameter的一个子类,除了NamedParameter,还有以下几种子类拱Resolve时使用:

参数类型

参数说明

NamedParameter

根据名称进行匹配

PositionalParameter

根据索引进行匹配,注意:起始索引为0

TypedParameter

根据类型进行匹配,注意:传入多个相同类型的TypedParameter,所有该类型的参数都将采用第一个TypedParameter的值

ResolvedParameter

接收两个Func参数,两个Func签名都接收两个相同的参数ParameterInfo和IComponmentContext,第一个参数为参数的信息(常使用放射的朋友应该熟悉),第二个参数还是当做IContainer使用就好了。第一个Func的返回值为bool,表明当前这个ResolvedParameter是否使用当前匹配到的参数,如果返回true,则会执行第二个Func;第二个Func返回一个object对象,用于填充构造参数值。

下面有一个这些Parameter使用的示例供参考:

class Program
{static void Main(string[] args){var builder = new ContainerBuilder();builder.RegisterType<ParameterClass>();var container = builder.Build();container.Resolve<ParameterClass>(new NamedParameter("value", "namedParameter"),      //匹配名字为value的参数new TypedParameter(typeof (int), 1),                //匹配类型为int的参数new PositionalParameter(4, "positionalParameter"),  //匹配第五个参数(注意,索引位置从0开始)new TypedParameter(typeof (int), -1),               //这个将被抛弃,因为前面已经有一个类型为int的TypedParameternew ResolvedParameter(//第一个Func参数用于返回参数是否符合要求,这里要求参数是类,且命名空间不是System开头,所以第四个参数将会匹配上(pi, cc) => pi.ParameterType.IsClass && !pi.ParameterType.Namespace.StartsWith("System"),//第二个Func参数在第一个Func执行结果为true时执行,用于给参数赋值,也就是第四个参数的值为这个Func的执行结果(pi, cc) => new Temp {Name = "resolveParameter"}));// 最后的输出结果为: {x:1, y:1, value:'namedParameter', temp.Name:'resolveParameter', obj:'positionalParameter'}Console.Write("Press any key to continue...");Console.ReadKey();}
}class ParameterClass
{public ParameterClass(int x, int y, string value, Temp temp, object obj){Console.WriteLine("{{x:{0}, y:{1}, value:'{2}', temp.Name:'{3}', obj:'{4}'}}", x, y, value, temp.Name, obj);}
}class Temp
{public string Name { get; set; }
}

转载于:https://www.cnblogs.com/GnailGnepGnaw/p/10757340.html

Autofac之自动装配相关推荐

  1. Autofac 组件、服务、自动装配 《第二篇》

    一.组件 创建出来的对象需要从组件中来获取,组件的创建有如下4种(延续第一篇的Demo,仅仅变动所贴出的代码)方式: 1.类型创建RegisterType AutoFac能够通过反射检查一个类型,选择 ...

  2. spring Bean自动装配

    spring Bean自动装配 自动装配是使用spring满足bean依赖的一种方式. spring会在应用上下文中为某个bean寻找其依赖的bean. spring自动装配需要从两个角度来实现,或者 ...

  3. 详解Spring中Bean的自动装配~

    目录 1. 环境搭建 2. byName.byType 3. 使用注解实现自动装配 @Autowired @Resource 小结 自动装配是Spring满足bean依赖的一种方式 Spring会在上 ...

  4. 【spring】自动装配

    山顶洞人方法:aotowire UserDao.java 代码实现: public class UserDao {private DBUtil dbu;public DBUtil getDbu() { ...

  5. springboot自动装配原理笔记一

    思维导图 太长放不了截图,就看大纲吧. 从启动类的@SpringBootApplication注解开始,探究其自动装配的原理 结论 整合javaEE,解决方案和自动装配的东西都在spring-boot ...

  6. java 装配_java – 无法自动装配方法

    我收到了这个错误 org.springframework.beans.factory.BeanCreationException: Could not autowire method: 这是我的spr ...

  7. Spring 自动装配及其注解

    一.属性自动装配 首先,准备三个类,分别是User,Cat,Dog.其中User属性拥有Cat和Dog对象. 1 package com.hdu.autowire; 2 3 public class ...

  8. Spring@Autowired注解与自动装配

    1   配置文件的方法 我们编写spring 框架的代码时候.一直遵循是这样一个规则:所有在spring中注入的bean 都建议定义成私有的域变量.并且要配套写上 get 和 set方法. Boss ...

  9. Spring框架学习day_02:组件扫描 / 注解内部读解 / 组件扫描中配置作用域和生命周期 / 解耦 / 自动装配(两种方式) / 读取文件

    1. 组件扫描 首先,必须让Spring扫描组件所在的包,并且,组件类的声明之前必须添加@Component注解! 其实,除了@Component注解以外,还可以使用以下注解实现同样的效果: @Con ...

最新文章

  1. NSight Compute 用户手册(上)
  2. 玩转SCVMM中的更新基线,实现虚拟平台基础服务器补丁自动更新
  3. 译:Spring Data Repository 不区分大小写查询
  4. 《maven实战》笔记(2)----一个简单maven项目的搭建,测试和打包
  5. linux下使用fread读socket套接字的注意点
  6. js split参数为无效字符_互联网前端开发技术JavaScript字符串类型详解
  7. Android安全防护之旅---Android应用反调试操作的几种方案解析
  8. 【学习笔记9】Linux常用命令6 - 压缩解压命令
  9. cachecloud部署和创建机器
  10. 4gl程式debug常用技巧
  11. mysql mtq_GoLang 连接 Mysql 数据库
  12. win10下禁用全角半角Kill-Shift-Space
  13. PLM,是一个英文缩写,有2个含义,一是表示产品生命周期管理(product lifecycle management,PLM),...
  14. mysqlbug日记
  15. str.charAt(0);
  16. 走访最没存在感的省份之一,经济仍有潜力
  17. 财务共享服务中心如何实现效率翻番?
  18. 在新手机里如何找回上一个手机便签里的内容
  19. Android,JCVideoPlayerStandard,节操,视频播放
  20. RE-实验吧分道扬镳/Just Click

热门文章

  1. php 空函数,PHP 中函数 isset(), empty(), is_null() 的区别
  2. jquery扩张函数
  3. 阿拉伯语排版设计_针对说阿拉伯语的用户的测试和设计
  4. Vue2 彻底从 Flow 重构为 TypeScript,焕然一新!
  5. nginx修改upstream不重启的方法(ngx_http_dyups_module模块)
  6. Echarts多任务可视化之再优化
  7. fgetcsv()函数
  8. Jmeter-3.0的源码导入eclipse并执行
  9. Directx11学习笔记【二】 将HelloWin封装成类
  10. HDOJ 1228 A+B(map水题)