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

如何在Zenject中为BaseUnit传递自身引用至状态工厂?

如何在Zenject状态工厂中注入BaseUnit自身引用

嘿,这个问题我之前用Zenject做状态机架构的时候也碰到过!核心要解决的是让每个BaseUnit实例的专属UnitStateFactory能拿到自己的宿主引用,下面给你几个贴合Zenject最佳实践的解决方案:

方案1:用实例绑定+子容器(适合MonoBehaviour场景)

因为BaseUnit是MonoBehaviour,每个实例都是独立的,我们可以给每个BaseUnit创建一个专属的子容器,把自身实例绑定进去,再注入UnitStateFactory:

首先,确保你的UnitStateFactory构造函数已经接收BaseUnit参数:

public class UnitStateFactory
{
    private readonly UnitMoveState.Factory _moveStateFactory;
    private readonly UnitActiveState.Factory _activeStateFactory;
    private readonly BaseUnit _owningUnit;

    public UnitStateFactory(
        UnitMoveState.Factory moveStateFactory,
        UnitActiveState.Factory activeStateFactory,
        BaseUnit owningUnit)
    {
        _moveStateFactory = moveStateFactory;
        _activeStateFactory = activeStateFactory;
        _owningUnit = owningUnit;
    }

    // 状态创建方法,比如生成移动状态
    public IUnitState CreateMoveState()
    {
        return _moveStateFactory.Create();
    }
}

然后在BaseUnit的Awake方法里手动初始化子容器并注入:

public class BaseUnit : MonoBehaviour
{
    [Inject]
    public UnitStateFactory StateFactory { get; private set; }

    private void Awake()
    {
        // 为当前Unit实例创建专属子容器
        var subContainer = new DiContainer();
        
        // 把自身实例绑定到容器中,确保Factory能拿到
        subContainer.BindInstance(this).AsSingle();
        
        // 绑定各个状态的工厂和总状态工厂
        subContainer.Bind<UnitMoveState.Factory>().AsSingle();
        subContainer.Bind<UnitActiveState.Factory>().AsSingle();
        subContainer.Bind<UnitStateFactory>().AsSingle();
        
        // 注入当前Unit的依赖(包括StateFactory)
        subContainer.Inject(this);
    }
}

方案2:带参数的状态工厂(更灵活,避免循环依赖)

如果不想用子容器,也可以让状态的Factory接受BaseUnit作为创建参数,这样UnitStateFactory只需要持有自身的Unit引用,创建状态时传递进去:

首先修改状态类的Factory为带参数的版本:

public class UnitMoveState : IUnitState
{
    private readonly BaseUnit _unit;

    // 构造函数接收BaseUnit
    public UnitMoveState(BaseUnit unit)
    {
        _unit = unit;
    }

    // 定义带参数的Zenject工厂
    public class Factory : PlaceholderFactory<BaseUnit, UnitMoveState> { }
}

然后在UnitStateFactory里创建状态时传入自身持有的Unit:

public IUnitState CreateMoveState()
{
    // 把当前Factory持有的Unit传给状态工厂
    return _moveStateFactory.Create(_owningUnit);
}

这种方式不需要处理容器的上下文绑定,更适合状态需要动态切换宿主的场景。

方案3:用MonoInstaller做上下文绑定(最规范的Zenject方式)

如果你的项目已经在用Zenject的场景安装器,可以给BaseUnit配一个专属的MonoInstaller,把自身实例绑定到容器中:

先创建安装器类:

public class BaseUnitInstaller : MonoInstaller<BaseUnitInstaller>
{
    // 在Inspector中把当前BaseUnit拖进来
    public BaseUnit TargetUnit;

    public override void InstallBindings()
    {
        // 绑定当前Unit实例为单例
        Container.BindInstance(TargetUnit).AsSingle();
        
        // 绑定状态工厂和总工厂
        Container.Bind<UnitMoveState.Factory>().AsSingle();
        Container.Bind<UnitActiveState.Factory>().AsSingle();
        Container.Bind<UnitStateFactory>().AsSingle();
    }
}

然后在BaseUnit的GameObject上挂载这个BaseUnitInstaller,并把TargetUnit字段设置为自身,这样Zenject在加载场景时会自动完成绑定,把正确的BaseUnit实例注入到UnitStateFactory中。

注意事项

  • 如果出现循环依赖(BaseUnit依赖UnitStateFactory,同时UnitStateFactory依赖BaseUnit),Zenject的单例绑定会自动处理这种情况,不用额外配置。
  • 确保所有状态类的构造函数都正确接收BaseUnit参数,Zenject会自动完成注入(如果用方案1或3),或者通过工厂参数传递(方案2)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:36:00