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);
}
此题具体针对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);
}