有什么方法可以命名相同类型的倍数吗?

2023-12-25

注意:使用.NET Core 2.0 [Microsoft.Extensions.DependencyInjection]。

这是我想做的:

IServiceCollection collection = new ServiceCollection();
collection.AddSingleton<IMyReusableViewModel, MyReusableViewModel>(nameof(View1));
collection.AddSingleton<IMyReusableViewModel, MyReusableViewModel>(nameof(View2));

但我无法找到一种方法来命名添加到集合中的服务。如果使用的类型重复但未指定名称,则该集合似乎只是用新服务覆盖现有服务。理想情况下,我能够重用一个类型,但通过提供名称来区分它。

请忽略这个人为的例子。

问:这可能吗?


鉴于以下事实服务描述符类 https://github.com/aspnet/DependencyInjection/blob/d5e5aa703297b164b21ba4ad3fdff81c854ce009/src/DI.Abstractions/ServiceDescriptor.cs没有Name属性或任何设置字符串标识符的方法,并且用于解析服务的类被标记为内部,我想说答案是no.


然而,构建自己的扩展来伪造它并不是很困难。

命名服务描述符

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();
    }
}

扩展方法

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:也就是说,我不会推荐这种方法。如果您需要此类功能,则表明应用程序设计不充分。设计模式如抽象工厂 https://sourcemaking.com/design_patterns/abstract_factory or Strategy https://stackoverflow.com/a/32415954可能需要填补空白,而不需要诉诸命名类型注册或滥用容器作为服务定位器 http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/.

或者,您可以使用支持此功能的第 3 方 DI 容器。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有什么方法可以命名相同类型的倍数吗? 的相关文章

随机推荐