有什么办法可以命名相同类型的倍数? [英] Any way to name multiples of the same type?
问题描述
注意:使用.NET Core 2.0 [Microsoft.Extensions.DependencyInjection]。
我想做的是:
IServiceCollection集合= new ServiceCollection();
collection.AddSingleton< IMyReusableViewModel,MyReusableViewModel>(nameof(View1));
collection.AddSingleton< IMyReusableViewModel,MyReusableViewModel>(nameof(View2));
但是我想不出一种方法来命名添加到集合中的服务。如果使用的类型重复而未指定名称,则该集合似乎只是用新的覆盖现有服务。理想情况下,我可以重用类型,但可以通过提供名称来区分它。
请忽略人为的示例。
问:这可能吗?
考虑到 ServiceDescriptor类没有 Name
属性或任何设置字符串标识符的方式,并且用于解析服务的类都标记为内部,我想答案是否
但是,构建自己的扩展程序来伪造它并不是很困难。
NamedServiceDescriptor
class NamedServiceDescriptor
{
public NamedServiceDescriptor(string name ,输入serviceType)
{
this.Name = name;
this.ServiceType = serviceType;
}
公共字符串名称{get;私人套装; }
public Type ServiceType {get;私人套装; }
公共替代布尔值Equals(object obj)
{
if(!(obj是NamedServiceDescriptor))
返回false;
var other =(NamedServiceDescriptor)obj;
返回Name.Equals(other.Name,StringComparison.OrdinalIgnoreCase)&&
ServiceType.Equals(other.ServiceType);
}
公共重写int GetHashCode()
{
返回Name.GetHashCode()^
ServiceType.GetHashCode();
}
}
扩展方法
公共静态类ServiceCollectionExtensions
{
内部静态只读IDictionary< NamedServiceDescriptor,Type> nameToTypeMap
=新的ConcurrentDictionary< NamedServiceDescriptor,Type>();
公共静态IServiceCollection AddSingleton< TService,TImplementation>(
此IServiceCollection serviceCollection,
字符串名称)
其中TService:class其中TImplementation:class,TService
{
nameToTypeMap [new NamedServiceDescriptor(name,typeof(TService))]
= typeof(TImplementation);
return serviceCollection.AddSingleton< TImplementation>();
}
}
公共静态类ServiceProviderExtensions
{
公共静态T GetService< T>(此IServiceProvider提供者,字符串名称)
{
if(provider == null)
throw new ArgumentNullException(nameof(provider));
if(string.IsNullOrEmpty(name))
抛出新的ArgumentNullException(nameof(name));
ServiceCollectionExtensions.nameToTypeMap.TryGetValue(
新的NamedServiceDescriptor(name,typeof(T)),out Type ImplementationType);
return(T)provider.GetService(implementationType);
}
}
用法
公共接口IMyReusableViewModel {}
公共类MyReusableViewModel1:IMyReusableViewModel {}
公共类MyReusableViewModel2:IMyReusableViewModel {}
IServiceCollection collection = new ServiceCollection();
collection.AddSingleton< IMyReusableViewModel,MyReusableViewModel1>( View1);
collection.AddSingleton< IMyReusableViewModel,MyReusableViewModel2>( View2);
公共类MyService
{
私人只读IServiceProvider提供程序;
public MyService(IServiceProvider provider)
{
this.provider = provider;
}
public void DoSomething()
{
var view1 = provider.GetService< IMyReusableViewModel>( View1);
var view2 = provider.GetService< IMyReusableViewModel>( View2);
// ...
}
}
< blockquote>
注意:也就是说,我不推荐这种方法。如果需要此类功能,则表明应用程序设计不充分。一种设计模式,例如抽象工厂或可能需要采取策略,而无需诉诸命名类型注册或滥用容器作为服务定位器。
或者,您可以使用第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.
Please ignore the contrived example.
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");
// ...
}
}
NOTE: That said, I wouldn't recommend this approach. If you require such functionality, it is a sign that the application design is inadequate. A design pattern such as Abstract Factory or Strategy may be what is needed to fill the void without resorting to naming type registrations or abusing the container as a Service Locator.
Alternatively, you could use a 3rd party DI container that supports this functionality.
这篇关于有什么办法可以命名相同类型的倍数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!