Denpendcy Injection 8.0新功能——KeyedService
Denpendcy Injection 8.0新功能——KeyedService
本文只介绍 .NET Denpendcy Injection 8.0新功能——KeyedService,假定读者已熟练使用之前版本的功能。
注册带Key的类
8.0之前,注册一个类往往是AddSingleton<IFoo, Foo>(),8.0添加了一个新功能:“可以注册一个带Key的类”AddKeyedSingleton<IFoo, Foo>("keyA")。获取服务方法由GetService<IFoo>()变成了GetKeyedService<IFoo>("keyA"),并且调用这两个方法创建出来的对象是不同的。

如果想通过构造函数注入,只需要在参数前面加上特性[FromKeyedServices("keyA")] 即可,特性里的参数就是key的名字。如果想在构造函数中获取key的值则使用特性[ServiceKey]。我们还可以注册时把key设置为KeyedService.AnyKey(这是框架提供的类),只需使用任意非null值作为key就可以获取对象。暂时不支持使用通配符匹配,也许以后会加......

class Bar : IBar
{
public Bar([ServiceKey] int key, [FromKeyedServices("keyA")] IFoo foo, IServiceProvider root)
{
//注意:key的类型要和调用时一致。
Console.WriteLine($"key:{key},Compare:{foo == root.GetKeyedService<IFoo>("keyA")}");
}
}
public static class KeyedService
{
/// Represents a key that matches any key.
public static object AnyKey { get; } = new AnyKeyObj();
private sealed class AnyKeyObj
{
public override string? ToString() => "*";
}
}
深入理解
8.0之前,获取一个对象需要用到的一个“标识”,比如调用GetService<IFoo>(),这个“标识”就是IFoo;也就是ServiceDescriptor里面的ServiceType。而在8.0后“标识”变成了IFoo+"keyA",也就是ServiceDescriptor里面的ServiceType+新增的ServiceKey。
public class ServiceDescriptor
{
public object? ServiceKey { get; }
public Type? ImplementationType => _implementationType;
public Type ServiceType { get; }
public ServiceLifetime Lifetime { get; }
对于以前注册的类,ServiceKey默认是null,所以“标识”就是ServiceKey+null。调用GetService<IFoo>()就等于调用GetKeyedService<IFoo>(null)。

再举一个例子:

//类型的注册信息放在_descriptorLookup,8.0前,是通过ServiceType作为字典的键,
//8.0是把ServiceIdentifier(也就是ServiceKey+ServiceType)作为字典的键
//7.0
private readonly Dictionary<Type, ServiceDescriptorCacheItem> _descriptorLookup = new();
//8.0
private readonly Dictionary<ServiceIdentifier, ServiceDescriptorCacheItem> _descriptorLookup = new();
internal readonly struct ServiceIdentifier : IEquatable<ServiceIdentifier>
{
public object? ServiceKey { get; }
public Type ServiceType { get; }
}

循环引用
前面讲到可以通过[ServiceKey]获取调用时的Key;而没有注册key的服务是无法在构造函数中注入key的值。通过这个功能可以解决循环引用的问题,先看代码。
class Foo : IFoo
{
//这个构造函数给GetService<IFoo>()使用
public Foo()
{
this.Num = 10;
}
//这个构造函数给GetKeyedServices<IFoo>("keyA")使用
public Foo([ServiceKey] string key, IFoo foo)
{
Console.WriteLine($"key:{key},this.Num:{this.Num},foo.Num:{foo.Num}");
}
public int Num { get; set; }
}

代码执行流程:
- 1.DI首先获取Foo的所有构造函数并且按构造函数的参数从多到少进行排序
- 2.遍历所有构造函数,首先获取参数最多的构造函数
Foo([ServiceKey] string key, IFoo foo),开始判断构造函数的参数能否被DI创建 - 3.DI首先判断
string key这个参数,能够创建;然后继续判断第二个参数IFoo foo能否被创建 - 4.重复第一步
- 5.重复第二步
- 6.DI首先判断
string key这个参数,不能够创建;所以无法调用构造函数Foo([ServiceKey] string key, IFoo foo)创建Foo实例 - 7.继续遍历构造函数,第二个构造函数是无参的,DI能够创建
foo对象。 - 8.对于
GetKeyedServices<IFoo>("keyA"),是使用的这个构造函数Foo([ServiceKey] string key, IFoo foo)创建的对象。IFoo foo是使用无参构造函数创建的。
注意点:
- 参数
[ServiceKey] string key一定要写在参数IFoo foo前面,否则就会循环引用 - 注册服务时,要注册两种(带key的和不带key的都要注册)
AddScoped<IFoo, Foo>() .AddKeyedScoped<IFoo, Foo>("keyA")
总结
以前的用法往往是接口对应实现类,通过DI获取对象,只需要知道接口的名字,就可以通过GetService方法或者构造函数注入获取对象。
现在是接口+key对应实现类,通过DI获取对象,需要知道接口+key。如果key为null就和以前的用法一模一样。
结束。第一次写文章如有错误,欢迎各位批评指点,谢谢!
Denpendcy Injection 8.0新功能——KeyedService的更多相关文章
- VS2015预览版中的C#6.0 新功能(二)
VS2015预览版中的C#6.0 新功能(一) VS2015预览版中的C#6.0 新功能(三) 自动属性的增强 只读自动属性 以前自动属性必须同时提供setter和getter方法,因而只读属性只能通 ...
- VS2015预览版中的C#6.0 新功能(三)
VS2015预览版中的C#6.0 新功能(一) VS2015预览版中的C#6.0 新功能(二) Using static 使用using StaticClass,你可以访问StaticClass类里的 ...
- VS2015预览版中的C#6.0 新功能(一)
VS2015预览版中的C#6.0 新功能(二) VS2015预览版中的C#6.0 新功能(三) VS2015的预览版在11月12日发布了,下面让我们来看看C#都提供了哪些新的功能. 字符串添写(Str ...
- REDGATE SQLPROMPT 6.0新功能
原文:REDGATE SQLPROMPT 6.0新功能 REDGATE SQLPROMPT 6.0新功能 下载地址:http://files.cnblogs.com/lyhabc/SQLPrompt6 ...
- unity5.0新功能-布料、动画系统
原作者:只待苍霞 这一章讲一下布料系统, 这次的布料系统有很大的改良.Unity4中, 需要对SkinnedMeshRenderer使用SkinnedCloth, 或者对Cloth Renderer使 ...
- unity5.0新功能
原作者 只待苍霞 章节1: 先来两个最关心的新功能, 第一章先讲PBS, 第二章讲光影GI.说到PBS, 首先应该想到的是Unity自带的两个新的Shader, 分别是Standard以及Standa ...
- Eviews 9.0新功能——估计方法(ARDL、面板自回归、门限回归)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 9.2 估计功能 eviews9.0下载链接: ...
- Redis 4.0新功能介绍
Redis 的作者 antirez 在三天之前通过博客文章<The first release candidate of Redis 4.0 is out>发布了 Redis 4.0 的第 ...
- ASP.NET Core 2.0 新功能汇总
前言 ASP.NET Core 的变化和发展速度是飞快的,当你发现你还没有掌握 ASP.NET Core 1.0 的时候, 2.0 已经快要发布了,目前 2.0 处于 Preview 1 版本,意味着 ...
- drone 1.0 新功能试用以及说明
drone 1.0 rc 已经发布,新的功能很强大,界面比旧版本更加人性化,和git 的集成也更高了 测试环境准备 试用gogs 做为git 管理工具 docker-compose 文件 versio ...
随机推荐
- http_basic认证(401)爆破
Http Basic认证(401)爆破 hydra,burpsuit 在thm:https://tryhackme.com/room/toolsrus 遇到了这个问题,但这个用的工具是hydra,想起 ...
- shell编程-文件归档
需求说明:设置定时任务,每天凌晨1点进行将指定目录(/root/scripts)下文件按照archive_目录名_年月日.tar.gz的格式归档存放到/root/archive 路径下. 1.编写脚本 ...
- 做副业的我很迷茫,但ChatGPT却治好了我——AI从业者被AI模型治愈的故事
迷茫,无非就是不知道自己要做什么,没有目标,没有方向. 当有一个明确的目标时,往往干劲十足.但做副业过程中,最大的问题往往就是 不知道自己该干什么. 干什么?怎么干?干到什么程度?这是做副业(甚至任何 ...
- WWDC2023 Session系列:探索XCode15新特性
一.版本说明 XCode 15 beta 发布于 2023 年 6月5日, 可支持 macOS 13.3 或以上版本, 你可以按需下载需要的平台. 二.新增特性 1.代码智能提示 (Code comp ...
- Jupyter Notebook运行中内核挂掉
Jupyter Notebook运行中内核挂掉了 有人说可能是版本冲突,由于我的都是最新版本,因此更新版本并未解决该问题. 最后发现有人通过这行代码解决了 import os os.environ[& ...
- P3134 [USACO16JAN] Lights Out G 关灯
P3134 [USACO16JAN] Lights Out G 关灯 目录 P3134 [USACO16JAN] Lights Out G 关灯 [USACO16JAN] Lights Out G 题 ...
- 在DevExpress的GridView的列中,动态创建列的时候,绑定不同的编辑处理控件
在使用DevExpress的GridView的时候,我们为了方便,往往使用一些扩展函数,动态创建GridView列的编辑控件对象,然后我们可以灵活的对内容进行编辑或者使用一些弹出的对话框窗体进行处理内 ...
- k8s+containerd安装
准备环境 准备两台服务器节点,如果需要安装虚拟机,可以参考<wmware和centos安装过程> 机器名 IP 角色 CPU 内存 centos01 192.168.109.130 mas ...
- DevOps|服务治理与服务保障实践指南
朱晋君@君哥聊技术 我自己为了消化里边的内容,整理了一个脑图,希望对你有帮助. 凌晨四点被公司的监控告警叫醒了,告警的原因是生产环境跑批任务发生故障.即刻起床处理故障,但还是花了不少时间才解决. 这次 ...
- Uncaught TypeError: Failed to set the 'currentTime' property on 'HTMLMediaElement': The provided double value is non-finite.
musicSeekTo: function(value){this.audio.currentTime = this.audio.duration*value; }, musicVoiceSeekTo ...