IServiceProvider.GetServices<T>() 是不是总是按注册顺序返回可用的服务实现?

Posted

技术标签:

【中文标题】IServiceProvider.GetServices<T>() 是不是总是按注册顺序返回可用的服务实现?【英文标题】:Does IServiceProvider.GetServices<T>() always returns the available service implementations in the registration order?IServiceProvider.GetServices<T>() 是否总是按注册顺序返回可用的服务实现? 【发布时间】:2021-08-28 15:11:43 【问题描述】:

这个问题专门针对 ASP.NET core 3.1 和内置的依赖注入容器(Microsoft DI)。

Microsoft documentation 和 this *** question 确认,当为同一服务类型注册了多个实现类型时,Microsoft DI 容器始终通过遵守注册顺序来解析 IEnumerable&lt;TService&gt;。订单有保证,并且有明确的记录。

有谁知道IServiceProvider.GetServices&lt;T&gt;() 方法是否同样适用?

如果上述问题的答案是肯定的,即使在以下示例中(同一类的两个不同实例注册为同一服务类型的实现),这是否也成立?

public interface IService 

public sealed class Foo : IService 

var foo1 = new Foo();
var foo2 = new Foo();

services.AddSingleton<IService>(foo1);
services.AddSingleton<IService>(foo2);

var implementations = serviceProvider.GetServices<IFoo>();

// is it guaranteed that implementations[0] == foo1 and implementations[1] == foo2 ???

【问题讨论】:

我不知道答案,但当您无法完全控制订单或提供集合的方法未明确保证时,我总是建议不要依赖集合中项目的顺序特定的顺序(例如将排序函数指定为方法的输入时)。否则,您将依赖可能随时更改的实现细节。 简短的回答是肯定的,因为在内部 GetServices&lt;T&gt; 扩展方法解析 IEnumerable&lt;T&gt; 与将 IEnumerable&lt;T&gt; 作为注入依赖项的构造函数相同 【参考方案1】:

简短的回答是肯定的,因为内部 GetServices* 扩展方法解析 IEnumerable&lt;T&gt; 与将 IEnumerable&lt;T&gt; 作为注入依赖项的构造函数中相同

/// <summary>
/// Get an enumeration of services of type <typeparamref name="T"/> from the <see cref="IServiceProvider"/>.
/// </summary>
/// <typeparam name="T">The type of service object to get.</typeparam>
/// <param name="provider">The <see cref="IServiceProvider"/> to retrieve the services from.</param>
/// <returns>An enumeration of services of type <typeparamref name="T"/>.</returns>
public static IEnumerable<T> GetServices<T>(this IServiceProvider provider)

    if (provider == null)
    
        throw new ArgumentNullException(nameof(provider));
    

    return provider.GetRequiredService<IEnumerable<T>>();

/// <summary>
/// Get an enumeration of services of type <paramref name="serviceType"/> from the <see cref="IServiceProvider"/>.
/// </summary>
/// <param name="provider">The <see cref="IServiceProvider"/> to retrieve the services from.</param>
/// <param name="serviceType">An object that specifies the type of service object to get.</param>
/// <returns>An enumeration of services of type <paramref name="serviceType"/>.</returns>
public static IEnumerable<object?> GetServices(this IServiceProvider provider, Type serviceType)

    if (provider == null)
    
        throw new ArgumentNullException(nameof(provider));
    

    if (serviceType == null)
    
        throw new ArgumentNullException(nameof(serviceType));
    

    Type? genericEnumerable = typeof(IEnumerable<>).MakeGenericType(serviceType);
    return (IEnumerable<object>)provider.GetRequiredService(genericEnumerable);

Source code

【讨论】:

以上是关于IServiceProvider.GetServices<T>() 是不是总是按注册顺序返回可用的服务实现?的主要内容,如果未能解决你的问题,请参考以下文章