问题描述
注意:使用 .NET Core 2.0 [Microsoft.Extensions.DependencyInjection].
这是我想要做的:
IServiceCollection collection = new ServiceCollection();collection.AddSingleton(nameof(View1));collection.AddSingleton(nameof(View2));
但我想不出一种方法来命名添加到集合中的服务.如果使用的类型重复而未指定名称,则该集合似乎只是用新服务覆盖现有服务.理想情况下,我可以重用一个类型,但通过提供一个名称来区分它.
请忽略人为的例子.
问:这可能吗?
鉴于 ServiceDescriptor 类 没有 Name
属性或任何设置字符串标识符的方式,用于解析服务的类被标记为内部,我会说答案是否.
但是,构建自己的扩展来伪造它并不是很困难.
命名服务描述符
类 NamedServiceDescriptor{public NamedServiceDescriptor(字符串名称,类型服务类型){this.Name = 名称;this.ServiceType = serviceType;}公共字符串名称 { 获取;私人订制;}公共类型服务类型 { 获取;私人订制;}公共覆盖布尔等于(对象 obj){if (!(obj is NamedServiceDescriptor))返回假;var other = (NamedServiceDescriptor)obj;返回 Name.Equals(other.Name, StringComparison.OrdinalIgnoreCase) &&ServiceType.Equals(other.ServiceType);}公共覆盖 int GetHashCode(){返回 Name.GetHashCode() ^ServiceType.GetHashCode();}}
扩展方法
公共静态类 ServiceCollectionExtensions{内部静态只读 IDictionary名称到类型映射= new ConcurrentDictionary();公共静态 IServiceCollection AddSingleton(这个 IServiceCollection serviceCollection,字符串名称)where TService : class where TImplementation : class, TService{nameToTypeMap[new NamedServiceDescriptor(name, typeof(TService))]= typeof(TI实现);return serviceCollection.AddSingleton();}}公共静态类 ServiceProviderExtensions{public static T GetService(这个 IServiceProvider 提供者,字符串名称){如果(提供者 == 空)throw new ArgumentNullException(nameof(provider));if (string.IsNullOrEmpty(name))throw new ArgumentNullException(nameof(name));ServiceCollectionExtensions.nameToTypeMap.TryGetValue(new NamedServiceDescriptor(name, typeof(T)), out Type implementationType);返回 (T)provider.GetService(implementationType);}}
用法
公共接口 IMyReusableViewModel { }公共类 MyReusableViewModel1 : IMyReusableViewModel { }公共类 MyReusableViewModel2 : IMyReusableViewModel { }IServiceCollection collection = new ServiceCollection();collection.AddSingleton("View1");collection.AddSingleton("View2");公共类 MyService{私有只读 IServiceProvider 提供者;公共 MyService(IServiceProvider 提供者){this.provider = 提供者;}公共无效 DoSomething(){var view1 = provider.GetService("View1");var view2 = provider.GetService("View2");//...}}
注意:也就是说,我不推荐这种方法.如果您需要此类功能,则表明应用程序设计不够完善.一种设计模式,例如 Abstract Factory 或 策略 可能是填补空白而不诉诸命名类型注册或滥用容器作为服务定位器.
或者,您可以使用支持此功能的第 3 方 DI 容器.
Note: using .NET Core 2.0 [Microsoft.Extensions.DependencyInjection].
Here's what I would like to do:
IServiceCollection collection = new ServiceCollection();
collection.AddSingleton<IMyReusableViewModel, MyReusableViewModel>(nameof(View1));
collection.AddSingleton<IMyReusableViewModel, MyReusableViewModel>(nameof(View2));
But I can't figure out a way to name services added to the collection. If the type used repeats without a name specified, the collection appears to simply overwrite the existing service with the new one. Ideally, I would be able to reuse a type, but differentiate it by supplying a name.
Q: Is this possible?
Given the fact that the ServiceDescriptor class doesn't have a Name
property or any way to set a string identifier and the classes for resolving services are marked internal, I would say the answer is no.
However, it's not very difficult to build your own extensions to fake it.
NamedServiceDescriptor
class NamedServiceDescriptor
{
public NamedServiceDescriptor(string name, Type serviceType)
{
this.Name = name;
this.ServiceType = serviceType;
}
public string Name { get; private set; }
public Type ServiceType { get; private set; }
public override bool Equals(object obj)
{
if (!(obj is NamedServiceDescriptor))
return false;
var other = (NamedServiceDescriptor)obj;
return Name.Equals(other.Name, StringComparison.OrdinalIgnoreCase) &&
ServiceType.Equals(other.ServiceType);
}
public override int GetHashCode()
{
return Name.GetHashCode() ^
ServiceType.GetHashCode();
}
}
Extension Methods
public static class ServiceCollectionExtensions
{
internal static readonly IDictionary<NamedServiceDescriptor, Type> nameToTypeMap
= new ConcurrentDictionary<NamedServiceDescriptor, Type>();
public static IServiceCollection AddSingleton<TService, TImplementation>(
this IServiceCollection serviceCollection,
string name)
where TService : class where TImplementation : class, TService
{
nameToTypeMap[new NamedServiceDescriptor(name, typeof(TService))]
= typeof(TImplementation);
return serviceCollection.AddSingleton<TImplementation>();
}
}
public static class ServiceProviderExtensions
{
public static T GetService<T>(this IServiceProvider provider, string name)
{
if (provider == null)
throw new ArgumentNullException(nameof(provider));
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException(nameof(name));
ServiceCollectionExtensions.nameToTypeMap.TryGetValue(
new NamedServiceDescriptor(name, typeof(T)), out Type implementationType);
return (T)provider.GetService(implementationType);
}
}
Usage
public interface IMyReusableViewModel { }
public class MyReusableViewModel1 : IMyReusableViewModel { }
public class MyReusableViewModel2 : IMyReusableViewModel { }
IServiceCollection collection = new ServiceCollection();
collection.AddSingleton<IMyReusableViewModel, MyReusableViewModel1>("View1");
collection.AddSingleton<IMyReusableViewModel, MyReusableViewModel2>("View2");
public class MyService
{
private readonly IServiceProvider provider;
public MyService(IServiceProvider provider)
{
this.provider = provider;
}
public void DoSomething()
{
var view1 = provider.GetService<IMyReusableViewModel>("View1");
var view2 = provider.GetService<IMyReusableViewModel>("View2");
// ...
}
}
Alternatively, you could use a 3rd party DI container that supports this functionality.
这篇关于有什么方法可以命名相同类型的倍数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!