unity3d 为什么使用Zenject(Unity)在抽象类State中实现IInitializable不起作用?

tyky79it  于 2023-01-02  发布在  其他
关注(0)|答案(2)|浏览(110)

我是Zenject世界的新手。我正在修改一个示例代码SampleGame1 (Beginner)(你可以查看完整的示例here),通过实现Iinitializable,现有的是IDisposable,所以现在有两个实现的接口。

public abstract class ShipState : IDisposable, IInitializable
{
    public abstract void Update();

    public virtual void Start()
    {
        // optionally overridden
    }

    public virtual void Dispose()
    {
        // optionally overridden
    }

    public virtual void OnTriggerEnter(Collider other)
    {
        // optionally overridden
    }

    public virtual void Initialize()
    {
        // optinally overridden
    }
}

目的是我想在其中一个状态中使用Initialize()方法,这样我就可以订阅该状态中的信号。

public override void Initialize()
{
    Debug.Log("Initializing ShipStateMoving");
    signalBus.Subscribe("ExampleSignal");
}

public override void Dispose()
{
    Debug.Log("Disposing ShipStateMoving");
    _ship.ParticleEmitter.gameObject.SetActive(false);
}

但是当我尝试实现这个方法时,Initialize()没有被调用,但是Dispose()被成功调用了...这是为什么呢?
如果我查看GameInstaller.cs中的InstallShip(),我不知道Idisposable是如何绑定的,但是为什么现有示例中Idisposable的实现被成功调用,而IInitializable没有被成功调用呢?

// I have no clue in this function why Idisposable is bound, there are no BindInterfaces in it.
void InstallShip()
{
    Container.Bind<ShipStateFactory>().AsSingle();

    // Note that the ship itself is bound using a ZenjectBinding component (see Ship
    // game object in scene hierarchy)

    Container.BindFactory<ShipStateWaitingToStart, ShipStateWaitingToStart.Factory>().WhenInjectedInto<ShipStateFactory>();
    Container.BindFactory<ShipStateDead, ShipStateDead.Factory>().WhenInjectedInto<ShipStateFactory>();
    Container.BindFactory<ShipStateMoving, ShipStateMoving.Factory>().WhenInjectedInto<ShipStateFactory>();
}
x33g5p2x

x33g5p2x1#

新年快乐!
总之,我建议修改Factory方法。
代码如下所示

public abstract class ShipState : IDisposable
{
    public abstract void Update();

    public virtual void Start()
    {
        // optionally overridden
    }

    public virtual void Dispose()
    {
        // optionally overridden
    }

    public virtual void OnTriggerEnter(Collider other)
    {
        // optionally overridden
    }
    
    public class ShipStateFactory: PlaceholderFactory<ShipState>
    {
        
    }

}
public class CustomShipStateFactory : IFactory<  ShipState  >
{
    private DiContainer _container;
        
    [Inject]
    public CustomShipStateFactory(DiContainer container)
    {
        _container = container;
    }     
        
    public ShipState Create()
    {
            
        ShipState shipstate = _container.Instantiate<ShipState>();
        // todo Initialize    
        return shipstate;

    }
        
}
public class SampleInstaller : MonoInstaller
{
        public override void InstallBindings()
        {
            Container
                .BindFactory<ShipState , ShipState.Factory>()
                .FromFactory<CustomShipStateFactory>()
        }
}

=为什么很难使用Initilized =
Zenject的初始化方法仅在绑定了IInitializable时才会激发。
在您编写的安装程序中,ShipState类及其Factory是Bind。
我认为ShipState类只是作为ShipState类绑定,因此不会调用Initilized。
因此,我想在安装程序中写入. BindInterfacesTo(),但我无法连接. From(),因为在生成示例之前没有示例。
这一次,我们需要在每次调用Create时将该示例绑定为IInitializable。
为了绑定,您需要创建一个同时创建的游戏对象,将一个游戏对象上下文附加到它,并将它与该游戏对象上下文单独绑定。
(我也推荐这种方式,如果ShipState是用一些gameobject创建的)
或者你可以使用. fromsubcontainerresolve()来完成它。但是我不知道这种方法的细节。

ttp71kqs

ttp71kqs2#

我不是Zenject的Maven,但我想我可以为您提供一些启发:

  • IDisposable不是Zenject的一部分,而是System的一部分,在documentation中可以看到,需要显式调用Dispose()方法,实际上如果接口绑定了Zenject,在context上调用OnDestroy()时,会在所有绑定的IDisposable上调用Dispose()方法。
  • 正如您在发布的安装程序中所看到的,只有工厂绑定,而没有接口,因此,如果调用Dispose,则会在其他地方调用它!
  • 最简单的方法是在ShipState提供的现有Start方法中编写您想要在Initialize中执行的操作,因为它在状态创建后立即被调用,以执行初始化。

相关问题