zenJect

Zenject框架(十)

2019-03-14  本文已影响0人  虫小白

安装器的运行时参数(Runtime Parameters For Installers)

通常在从安装器调用其他安装器时,希望能够传递参数。您可以通过将通用参数添加到正在使用的任何安装器基类以及运行时参数的类型来执行此操作。例如,使用非MonoBehaviour安装器时:

public class FooInstaller : Installer<string, FooInstaller>
{
    string _value;

    public FooInstaller(string value)
    {
        _value = value;
    }

    public override void InstallBindings()
    {
        ...

        Container.BindInstance(_value).WhenInjectedInto<Foo>();
    }
}

public class MainInstaller : MonoInstaller
{
    public override void InstallBindings()
    {
        FooInstaller.Install(Container, "asdf");
    }
}

或者在使用MonoInstaller预制件时:

public class FooInstaller : MonoInstaller<string, FooInstaller>
{
    string _value;

    // 注意这种情况下我们不能使用构造函数
    [Inject]
    public void Construct(string value)
    {
        _value = value;
    }

    public override void InstallBindings()
    {
        ...

        Container.BindInstance(_value).WhenInjectedInto<Foo>();
    }
}

public class MainInstaller : MonoInstaller
{
    public override void InstallBindings()
    {
        // 为使其正常工作,必须在存在以下预设体`Resources / My / Custom / ResourcePath.prefab`。
        //且该预设体上有FooInstaller组件
        FooInstaller.InstallFromResource("My/Custom/ResourcePath", Container, "asdf")

        // 如果未提供资源路径,则假定它存在于资源路径 
        // 'Resources/Installers/FooInstaller'下
        // 比如:
        // FooInstaller.InstallFromResource(Container, "asdf");
    }
}

ScriptableObjectInstallerMonoInstaller此方面的工作方式相同。

在Unity外部或者Dll中使用Zenject

如果您正在构建一些代码作为DLL然后将它们包含在Unity中,您仍然可以在安装器中为这些类添加绑定,唯一的限制是您必须使用构造函数注入。如果您想使用其他注入方法,例如成员注入或方法注入,那么您也可以这样做,但是在这种情况下,您需要为项目添加一个Zenject-Usage.dll,该文件可以在Zenject\Source\Usage目录中找到。此DLL还包括标准接口ITickable, IInitializable等,因此您也可以使用它们。

您还可以通过下载Zenject-NonUnity.zip在非Unity项目中使用zenject

最后,如果您尝试使用Unity生成的解决方案在Unity外部运行单元测试,在运行时,在Zenject代码尝试访问Unity API时中可能会遇到错误。您可以通过在生成的解决方案中添加ZEN_TESTS_OUTSIDE_UNITY条件编译来禁用此行为。

Zenject设置

可以通过ProjectContext上的settings属性自定义Zenject中的许多默认行为。这包括以下内容:

Zenject Warning: It is bad practice to call Inject/Resolve/Instantiate before all the Installers have completed!  This is important to ensure that all bindings have properly been installed in case they are needed when injecting/instantiating/resolving.  Detected when operating on type 'Foo'.

因此,如果您经常遇到此警告并且意识到您正在执行的操作的含义,那么您可以将此值设置为false以禁止它。

信号(Signals)

详见“Zenject框架(十八)- 信号”章节

使用工厂动态创建对象(Creating Objects Dynamically Using Factories)

详见后续信号章节

内存池(Memory Pools)

详见后续信号章节

更新/初始化顺序(Update / Initialization Order)

在许多情况下,特别是对于小型项目,类更新或初始化的顺序无关紧要。但是,在较大的项目中,更新或初始化顺序要认真对待。这在Unity中尤其明显,因为它往往很难预知多个Start(),Awake()或Update()以何种顺序被调用。不幸的是,Unity没有一种简单的方法控制这种情况(除了Edit -> Project Settings -> Script Execution Order,虽然这用起来可能很尴尬)

在Zenject中,默认情况下,多个ITickable和IInitializable按照添加顺序进行调用,但是对于对更新或初始化顺序有要求的情况,还有另一种方法有时更好:通过在安装器中明确指定其优先级。例如,在示例项目中,您可以在场景安装器中找到此代码:

public class AsteroidsInstaller : MonoInstaller
{
    ...

    void InitExecutionOrder()
    {
        // 很多情况下不需要关心执行顺序
        // 但在另一些情况下执行顺序很重要
        // 例如,我们要求AsteroidManager.Initialize
        // 总是在GameController.Initialize(以及Tick)之前调用
        // 我们可以这样做:
        Container.BindExecutionOrder<AsteroidManager>(-10);
        Container.BindExecutionOrder<GameController>(-20);

        // 注意销毁时以相反顺序进行
    }

    ...

    public override void InstallBindings()
    {
        ...
        InitExecutionOrder();
        ...
    }

}

这样,就不会因为不可预知的依赖项顺序导致错误发生。

请注意,给定BindExecutionOrder的值将适用于ITickable/ IInitializable和IDisposable(对于IDisposable为反向顺序)。

您还可以分别为每个特定接口分配优先级,如下所示:

Container.BindInitializableExecutionOrder<Foo>(-10);
Container.BindInitializableExecutionOrder<Bar>(-20);

Container.BindTickableExecutionOrder<Foo>(10);
Container.BindTickableExecutionOrder<Bar>(-80);

任何未分配优先级的ITickables,IInitializable或IDisposable都会自动优先为零。这允许您在未指定的类之前或之后执行具有显式优先级的类。例如,上面的代码将导致Foo.Initialize在Bar.Initialize之前被调用。

Zenject运行顺序

下面是运行使用Zenject的场景时会发生什么情况的更详细的视图。完全理解Zenject的工作原理可能很有用。

上一篇下一篇

猜你喜欢

热点阅读