IServiceProvider.GetServices<T>() 是否总是returns 注册顺序中的可用服务实现?

Does IServiceProvider.GetServices<T>() always returns the available service implementations in the registration order?

此题具体针对ASP.NET核心3.1和内置依赖注入容器(Microsoft DI)

Microsoft documentation and this Whosebug question 确认当为同一服务类型注册多个实现类型时,Microsoft DI 容器始终根据注册顺序解析 IEnumerable<TService>。订单有保证,并有明确记录。

有谁知道 IServiceProvider.GetServices<T>() 方法是否也是如此?

如果上述问题的答案是肯定的,那么即使在以下示例中也是如此(其中相同 class 的两个不同实例被注册为相同服务类型的实现)?

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* 扩展方法解析 IEnumerable<T> 与具有 IEnumerable<T> 作为注入依赖项的构造函数相同

/// <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