为什么 .NET Core DI 更喜欢接受 IEnumerable<T> 的构造函数而不是无参数构造函数?

Why .NET Core DI prefers constructor accepting IEnumerable<T> over parameterless one?

我有一个简单的服务接口:

public interface ICustomService
{
    bool ConstructedWithNoParameters { get; }
}

实现同样简单:

public class CustomService : ICustomService
{
    private readonly IEnumerable<int> _items;

    public CustomService()
    {
        _items = Enumerable.Empty<int>();

        ConstructedWithNoParameters = true;
    }

    public CustomService(IEnumerable<int> items)
    {
        _items = items ?? throw new ArgumentNullException(nameof(items));
    }

    public bool ConstructedWithNoParameters { get; }
}

请注意,根据调用的构造函数,ConstructedWithNoParameters 设置为 true

这里有一个简单的测试场景来测试它:

[Fact]
public void Test1()
{
    // Assert
    var serviceProvider = new ServiceCollection()
        .AddTransient<ICustomService, CustomService>()
        .BuildServiceProvider();

    // Act
    var customService = serviceProvider.GetRequiredService<ICustomService<int>>();

    // Arrange
    customService.ConstructedWithNoParameters.Should().BeTrue();
}

因为我没有指定应该如何构造实现,所以我希望调用无参数构造函数来初始化 CustomService 的新实例。但事实并非如此。上面的测试方法在以 ConstructedWithNoParametersfalse 结束断言时失败。在我看来,DI 解析器更喜欢接受 IEnumerable<int> 的其他构造函数而不是无参数构造函数。如果我只保留无参数构造函数可用,则测试通过。

我正在使用 .NET Core 2.2 和 XUnit 2.4.0 进行测试。

问题

为什么 DI 解析器更喜欢接受 IEnumerable<T> 而不是无参数的构造函数?

DI被设计成贪婪的,选择它能填充的参数最多的构造函数。可枚举参数仍然可以由 DI 使用空数组 构造,因此 DI 仍然可以进行重载。我相信这就是幕后发生的事情。