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

实现状态模式时检测到System.InvalidOperationException循环依赖问题

解决C#状态模式中水三态的依赖注入循环依赖问题

问题原因

你的代码中GasState构造函数依赖ILiquidState,而LiquidState又依赖IGasState,形成了循环依赖链(IGasState → ILiquidState → IGasState),导致依赖注入容器无法解析这些服务实例。

解决方案:使用状态工厂延迟获取实例

最合理的修复方式是引入状态工厂,让每个状态通过工厂获取目标转换状态,而不是直接注入互相依赖的实例。这种方式既打破循环依赖,又保持状态模式的封装性。

步骤1:定义状态工厂接口与实现

namespace LibraryExamples.Water
{
    public interface IWaterStateFactory
    {
        T GetState<T>() where T : IWaterState;
    }

    public class WaterStateFactory : IWaterStateFactory
    {
        private readonly IServiceProvider _serviceProvider;

        public WaterStateFactory(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public T GetState<T>() where T : IWaterState
        {
            return _serviceProvider.GetRequiredService<T>();
        }
    }
}

步骤2:重构所有状态类,依赖工厂而非直接依赖其他状态

修改GasState

namespace LibraryExamples.Water.States
{
    public class GasState : IGasState
    {
        private readonly IWaterStateFactory _stateFactory;

        public GasState(IWaterStateFactory stateFactory)
        {
            _stateFactory = stateFactory;
        }

        public IWaterState Heat()
        {
            Console.WriteLine("Already in a gaseous state. Heating has no effect.");
            return this;
        }

        public IWaterState Cool()
        {
            Console.WriteLine("Cooling gas (steam) turns it into liquid water.");
            return _stateFactory.GetState<ILiquidState>();
        }

        public void Describe()
        {
            Console.WriteLine("Current state: Gas");
        }

        public ILiquidState ToLiquidState()
        {
            return _stateFactory.GetState<ILiquidState>();
        }
    }
}

修改LiquidState

namespace LibraryExamples.Water.States
{
    public class LiquidState : ILiquidState
    {
        private readonly IWaterStateFactory _stateFactory;

        public LiquidState(IWaterStateFactory stateFactory)
        {
            _stateFactory = stateFactory;
        }

        public IWaterState Cool()
        {
            Console.WriteLine("Cooling liquid water turns it into solid water.");
            return _stateFactory.GetState<ISolideState>();
        }

        public IWaterState Heat()
        {
            Console.WriteLine("Heating liquid water turns into gas water");
            return _stateFactory.GetState<IGasState>();
        }

        public void Describe()
        {
            Console.WriteLine("Current state: Liquid"); // 修复原代码的状态描述错误
        }

        public IGasState ToGasState()
        {
            return _stateFactory.GetState<IGasState>();
        }

        public ISolideState ToSolidState()
        {
            return _stateFactory.GetState<ISolideState>();
        }
    }
}

修改SolidState

namespace LibraryExamples.Water.States
{
    public class SolidState : ISolideState
    {
        private readonly IWaterStateFactory _stateFactory;

        public SolidState(IWaterStateFactory stateFactory)
        {
            _stateFactory = stateFactory;
        }

        public IWaterState Heat()
        {
            Console.WriteLine("Heating solid water turns it into liquid water.");
            return _stateFactory.GetState<ILiquidState>();
        }

        public IWaterState Cool()
        {
            Console.WriteLine("Already solid. Cooling has no effect.");
            return this;
        }

        public void Describe()
        {
            Console.WriteLine("Current state: Solid");
        }

        public ILiquidState ToLiquidState()
        {
            return _stateFactory.GetState<ILiquidState>();
        }
    }
}

步骤3:在依赖注入容器中注册服务

// 注册工厂
services.AddScoped<IWaterStateFactory, WaterStateFactory>();
// 注册所有状态
services.AddScoped<IGasState, GasState>();
services.AddScoped<ILiquidState, LiquidState>();
services.AddScoped<ISolideState, SolidState>();
// 注册Water,指定初始状态(这里以液态为例)
services.AddScoped<IWater, Water>(sp => 
    new Water(sp.GetRequiredService<ILiquidState>())
);

替代方案:属性注入(不推荐)

如果不想引入工厂,可以使用属性注入来打破循环,但这种方式会隐藏依赖关系,不利于代码维护。示例如下(以ASP.NET Core为例):

public class GasState : IGasState
{
    // 标记为可注入属性
    public ILiquidState LiquidState { get; set; }

    // 提供无参构造函数
    public GasState() {}

    // 其他方法保持不变
}

需要在DI容器中配置允许属性注入:

services.AddScoped<IGasState, GasState>(sp => 
{
    var state = new GasState();
    state.LiquidState = sp.GetRequiredService<ILiquidState>();
    return state;
});
// 同理配置LiquidState

总结

推荐使用状态工厂模式,它不仅解决了循环依赖问题,还让状态转换逻辑更灵活,依赖关系清晰可见,符合依赖注入的最佳实践。

内容的提问来源于stack exchange,提问作者S. LaBani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 14:04:51