前面的学习一直使用的是直接注册类型并不是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链式编程的方式,如果希望多个接口或类型都与同一个类型进行关联,我们可以直接在表达式后面继续As

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>,这样就可以了。另一种方式就是AsSelf

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不知道应该返回哪个类型实例

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方法,这样,如果之前该接口/类型已经进行关联注册,则此次关联无效

关联类型与注册类型需要时继承/实现关系或为其本身

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

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

1、类型

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

builder.RegisterType<Worker>().As<IPerson>();  //IPerson类型的服务和Worker的组件连接起来,这个服务可以创建Worker类的实例

2、名字

服务可以进一步按名字识别。使用这种方式时,用 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();
}

3、键

有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注册的原因之一

Autofac之类型关联的更多相关文章

  1. IoC容器Autofac正篇之类型关联(服务暴露)(七)

    类型关联 类型关联就是将类挂载到接口(一个或多个)上去,以方便外部以统一的方式进行调用(看下例). 一.As关联 我们在进行手动关联时,基本都是使用As进行关联的. class Program { s ...

  2. IoC容器Autofac正篇之类型关联(服务暴露)(八)

    类型关联  类型关联就是将类挂载到接口(一个或多个)上去,以方便外部以统一的方式进行调用(看下例). 一.As关联 我们在进行手动关联时,基本都是使用As进行关联的. 1 2 3 4 5 6 7 8 ...

  3. WebStorm文件类型关联设置

    无意中创造了一个没有扩展名的文件,我选择了错误的文件类型关联.是js类型的,我却选成了文本,Ws每次编辑类型就成了txt文本,这个问题让我很苦恼,以下是我的解决方案. 错选的弹出框如下: 解决方案如下 ...

  4. Vim使用技巧:特定文件类型关联缩进

    Vim如何打开特定文件类型关联自动缩进呢?答案:将filetype indent on写入你的.vimrc文件中

  5. 背水一战 Windows 10 (99) - 关联启动: 关联指定的文件类型, 关联指定的协议

    [源码下载] 背水一战 Windows 10 (99) - 关联启动: 关联指定的文件类型, 关联指定的协议 作者:webabcd 介绍背水一战 Windows 10 之 关联启动 关联指定的文件类型 ...

  6. Windows的文件类型关联

    在用脚本语言开发时尤其是在windows环境下发现想自动在命令行环境下运行脚本必须要带着相应的解释器的路径才行,不然就会提示无法找到对应的命令,于是乎在<学习Ruby>这本书中对于文件类型 ...

  7. Autofac之类型注册

    本次主要学习一下Autofac中实现类型注册的几种方式,这里并不打算一开始就从基于接口开发的服务关联切入,而是先从一个简单的类型注册来学起,虽然实际开发中可能不会这么做,但是个人感觉从这里学起理解能能 ...

  8. Swift - 39 - 枚举类型关联默认值

    //: Playground - noun: a place where people can play import UIKit enum Month: Int { // 这么定义, 后面的Feb, ...

  9. 【Loadrunner】初学Loadrunner——参数化设置(Table类型关联数据库)

    参数化输入是Loadrrunner里面一个强大的功能,属于Loadrunner的高级使用技巧. 我们在登录系统的时候,需要输入一组定义的用户名和密码,比如有5个虚拟用户同时登陆系统,则这五个用户都用这 ...

随机推荐

  1. C++设计模式——模板方法模式

    模板方法模式 在GOF的<设计模式:可复用面向对象软件的基础>一书中对模板方法模式是这样说的:定义一个操作中的算法骨架,而将一些步骤延迟到子类中.TemplateMethod使得子类可以不 ...

  2. .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'

    原因是缺少了启动文件,startup_xxx.s,只需要把该文件添加到项目下即可,该文件如果找不到则重新建立工程,每个新的工程建立后系统都会询问是否添加启动文件,选择添加启动文件即可. 注意选择对应容 ...

  3. Xshell出现‘The remote SSH server rejected X11 forwarding request’解决办法

    当准备用Xshell进行远程连接的时候出现下面的情况: 那么跟着我来点击鼠标就ojbk了: 文件--->属性--->隧道 然后找打 把那个单选框的对号勾掉,然后点击确认就OK了!!

  4. 【转载】MySQL5.7 添加用户、删除用户与授权

    mysql -uroot -proot MySQL5.7 mysql.user表没有password字段改 authentication_string: 一. 创建用户: 命令:CREATE USER ...

  5. robot framework 上个用例的输出作为下个用例的输入 (Set Global Variable的用法)

    变量的作用域 通常情况下,每个变量默认都是局部变量. 一个case里的变量,作用域在这个case内部: 一个userkeyword里的变量,作用域在这个userkeyword内部: 一个文件型suit ...

  6. ycmd for emacs 代码自动补全

    YCMD FOR EMACS Table of Contents 1. 安装 1.1. 下载 1.2. 安装相关依赖 1.3. 更新submodules 1.4. 安装 2. 配置 1 安装   1. ...

  7. table切换jquery插件 jQuery插件写法模板 流程

    通过$.extend()来扩展jQuery 通过$.fn 向jQuery添加新的方法 通过$.widget()应用jQuery UI的部件工厂方式创建 通过$.extend()来扩展jQuery $. ...

  8. 重写 console.log()

    /*重写console.log*/ console.log = (function(mFun){ return function(str){ mFun.call(console,'hello! ' + ...

  9. 论文阅读笔记四十二:Going deeper with convolutions (Inception V1 CVPR2014 )

    论文原址:https://arxiv.org/pdf/1409.4842.pdf 代码连接:https://github.com/titu1994/Inception-v4(包含v1,v2,v4)   ...

  10. Spring Boot thymeleaf模版支持,css,js等静态文件添加

    Thymeleaf引入 Thymeleaf是一个Java模板引擎开发库,可以处理和生成HTML.XML.JavaScript.CSS和文本,在Web和非Web环境下都可以正常工作. 1.添加依赖包 & ...