有什么方法可以命名相同类型的倍数? [英] Any way to name multiples of the same type?

查看:24
本文介绍了有什么方法可以命名相同类型的倍数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:使用 .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.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆