.NET Core 依赖注入改造(1)- 命名服务
.NET Core 依赖注入改造(2)- 委托转换
.NET Core 依赖注入改造(3)- ILogger
.NET Core 依赖注入改造(4)- ActivatorUtilities
.NET Core 依赖注入改造(5)- Context
.NET Core 依赖注入改造(附1)- Autowired
一
.NET Standard 之后重新定义了一套相对独立和标准的依赖注入框架;
可以在Nuget中搜索 Microsoft.Extensions.DependencyInjection.Abstractions
和 Microsoft.Extensions.DependencyInjection
前者是框架的抽象的定义,后者是官方的实现;
这样做的好处是显而易见的,在开发组件时可以安装 Abstractions
按照标准接口、抽象类实现相关功能,不依赖具体实现;
而使用者就可以自由下载任意实现,例如非官方的Autofac.Extensions.DependencyInjection
也是一个不错的选择;
更多介绍网上的文章太多,就不展开了
二
使用nuget安装框架
然后写一个简单的例子
emmm,我知道用委托作为服务不是主流的用法,但是,我喜欢。。。
上面的例子中,我从Main方法中注入一个ToJsonString
和ToXmlString
的委托作为一个服务;
然后将ServiceProvider
放入上下文;
接着在另一个方法中从上下文获取ServiceProvider
,然后分别获取2个服务并使用它们;
三
实际开发中这样使用存在一个问题,注入和使用者都需要引用2个委托类型ToJsonString
和ToXmlString
;
而我想使用标准Func<T1,TResult>
时,尴尬的发现它们2个的声明是一毛一样的。
如果这样结果无疑是不正确的。
所以我想在有没有可能拓展出一种这样的命名服务
四
在Github上找到了Microsoft.Extensions.DependencyInjection的源码;
找到AddSingleton方法
public static IServiceCollection AddSingleton<TService>(
this IServiceCollection services,
TService implementationInstance)
where TService : class
{
// 一些无关代码
return services.AddSingleton(typeof(TService), implementationInstance); //这里调用了下面的方法
}
public static IServiceCollection AddSingleton(
this IServiceCollection services,
Type serviceType,
object implementationInstance)
{
// 一些无关代码
var serviceDescriptor = new ServiceDescriptor(serviceType, implementationInstance);
services.Add(serviceDescriptor);
return services;
}
这里看到了一个 ServiceDescriptor
对象,看名字应该是用来描述注册的服务的信息的;
从属性中也能看出,这里描述了服务实例类型,服务声明类型,声明周期,实例对象,实例创建方法;
所以估摸着从这里入手想办法加入服务名称的属性可以作为突破点。
五
but,先不着急,先看看获取服务是怎么做的;
这部分比较费时间,不详细展开了,感兴趣的可以自己下载源码之后细细研究;
基本顺序是:
- 获取服务是依赖接口
IServiceProvider
,所以需要先找到接口实现 - 根据
ServiceCollectionContainerBuilderExtensions.BuildServiceProvider
方法可以得到实现类是ServiceProvider
-
ServiceProvider.GetService
中用到了DynamicServiceProviderEngine
-
DynamicServiceProviderEngine
继承自CompiledServiceProviderEngine
-
CompiledServiceProviderEngine
继承自ServiceProviderEngine
-
ServiceProviderEngine
中用到了ServiceProviderEngineScope
,CallSiteExpressionBuilder
,CallSiteFactory
- 在
CallSiteFactory
中找到2个关键方法TryCreateOpenGeneric
和TryCreateExact
- 最终转了一圈发现,获取服务时,匹配规则就是很单纯的
serviceType == ServiceDescriptor.ServiceType
或者对于泛型服务来说serviceType.IsConstructedGenericType && serviceType.GetGenericTypeDefinition() == ServiceDescriptor.ServiceType
所以结论是,只要干涉 serviceType
的==
操作就可以实现自己获取服务的匹配逻辑;
六
说干就干,既然是干涉 serviceType
,那么 serviceType
必然是一个自定义对象,自己实现Equals
,GetHashCode
和==
;
所以接下来就是做一个 NamedType
类继承自Type
,由于Type
是抽象类,需要实现的部分太多了,所以可以继承TypeDelegator
来实现
拓展方法
七
现在回到最开始的方法运行下
八
github:https://github.com/blqw/blqw.DI/tree/master/src/blqw.DI.NamedService
nuget:https://www.nuget.org/packages/blqw.DI.NamedService