You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6依赖注入循环问题:同列表注册依赖解析失败原因探究

DI容器构造服务时的循环依赖问题解析

我正在尝试理解导致DI容器在构造依赖同列表中其他注册项的服务时出现循环的根本问题。以下是简化后的代码:

核心代码

public class ImplementationFactory
{
    private readonly IEnumerable<IImplementation> _implementations;

    public ImplementationFactory(IEnumerable<IImplementation> implementations)
    {
        _implementations = implementations;
    }

    public IEnumerable<IImplementation> GetAll(List<string> names)
    {
        return _implementations.Where(i => names.Contains(i.Name))
               ?? throw new NotSupportedException();
    }
}

public static class ImplementationNames
{
    public const string ImplementationOne = "One";

    public const string ImplementationTwo = "Two";
}

public interface IImplementation
{
    string Name { get; }
}

public class ImplementationOne : IImplementation
{
    public string Name { get; }

    public ImplementationOne(string name)
    {
        Name = name;
    }
}

public class ImplementationTwo : IImplementation
{
    public string Name { get; }

    public ImplementationTwo(string name)
    {
        Name = name;
    }
}

测试代码(触发循环依赖)

public class DependencyInjectionTests
{
    [Fact]
    public void CheckSecondImplementationCanLoadFirstImplementationUsingFactory()
    {
        try
        {
            var collection = new ServiceCollection();

            collection.AddTransient<IImplementation, ImplementationOne>(x =>
                new ImplementationOne(ImplementationNames.ImplementationOne));

            collection.AddTransient<ImplementationFactory>();

            collection.AddTransient<IImplementation, ImplementationTwo>(x =>
            {
                // 此处引发循环依赖
                var loadedImplementation = x.GetRequiredService<ImplementationFactory>()
                    .GetAll(new List<string> {ImplementationNames.ImplementationOne});

                return new ImplementationTwo(ImplementationNames.ImplementationTwo);
            });

            var provider = collection.BuildServiceProvider(validateScopes: true);

            provider.GetRequiredService<ImplementationFactory>()
                .GetAll(new List<string> {ImplementationNames.ImplementationTwo});
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            throw;
        }
    }
}

这是现有代码库中复杂DI解析问题的简化示例。我知道可以通过实现不同接口或工厂来解决,但想了解DI容器如何尝试解析第二个实现,以及为何在工厂委托中解析第一个注册项时会失败。


问题根源解析

1. DI容器解析ImplementationFactory的核心逻辑

当容器创建ImplementationFactory实例时,必须注入IEnumerable<IImplementation>——这意味着容器要一次性解析所有已注册的IImplementation实现,也就是ImplementationOne和ImplementationTwo。

2. 循环依赖链的形成

解析ImplementationTwo时,它的注册委托里调用了x.GetRequiredService<ImplementationFactory>(),但此时ImplementationFactory还未完成创建(它正等待ImplementationTwo被解析后注入到IEnumerable<IImplementation>中),于是形成闭环:

ImplementationFactory → 需要IEnumerable<IImplementation> → 需要ImplementationTwo → 需要ImplementationFactory

3. 单独解析ImplementationOne无问题的原因

ImplementationOne的注册委托不依赖任何其他服务,容器可以直接实例化它。但一旦ImplementationFactory需要所有IImplementation实现,容器就必须处理包含依赖的ImplementationTwo,触发循环。

4. validateScopes: true的放大作用

启用这个参数后,容器在构建ServiceProvider时就会提前验证服务的解析可行性,直接在构建阶段抛出循环依赖错误,而不是等到调用服务时才暴露问题。


内容的提问来源于stack exchange,提问作者Appa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 12:02:53