Zenject框架(七)

BindInterfacesTo 和 BindInterfacesAndSelfTo

如果你使用了ITickable, IInitializable, 和 IDisposable 接口,代码会变成这样:

Container.Bind(typeof(Foo), typeof(IInitializable), typeof(IDisposable)).To<Logger>().AsSingle();

这有点冗长,同时也不够理想,因为假如我稍后决定Foo不再使用Tick()或者Dispose(),那我就必须同时修改安装器。
一个更好的想法可能是只以下面的方式使用接口:

Container.Bind(new[] { typeof(Foo) }.Concat(typeof(Foo).GetInterfaces())).To<Foo>().AsSingle();

这种方式足够有用并且Zenject自定义了一个这种方式的绑定方法。上面的代码相当于:

Container.BindInterfacesAndSelfTo<Foo>().AsSingle();

现在,我们可以添加或者删除Foo的接口,而安装器不用修改。
在某些情况下,你可能只需要绑定的接口,并保持Foo对其他类隐藏。在这种情况下,您可以使用BindInterfacesTo方法:

Container.BindInterfacesTo<Foo>().AsSingle()

在该例中,相当于:

Container.Bind(typeof(IInitializable), typeof(IDisposable)).To<Foo>().AsSingle();

使用Unity的检视面板配置设置

将大部分代码编写为普通C#类而不是MonoBehaviour的一个后果是,您无法使用检查面板中配置数据。但是,您可以通过在Zenject中使用下面的方式来实现此功能:

public class Foo : ITickable
{
    readonly Settings _settings;

    public Foo(Settings settings)
    {
        _settings = settings;
    }

    public void Tick()
    {
        Debug.Log("Speed: " + _settings.Speed);
    }

    [Serializable]
    public class Settings
    {
        public float Speed;
    }
}

然后,在安装器中:

public class TestInstaller : MonoInstaller<TestInstaller>
{
    public Foo.Settings FooSettings;

    public override void InstallBindings()
    {
        Container.BindInstance(FooSettings);
        Container.BindInterfacesTo<Foo>().AsSingle();
    }
}

或者,等价的:

public class TestInstaller : MonoInstaller<TestInstaller>
{
    public Foo.Settings FooSettings;

    public override void InstallBindings()
    {
        Container.BindInterfacesTo<Foo>().AsSingle().WithArguments(FooSettings);
    }
}

现在,如果我们运行场景,我们可以在检视面板中实时调整Foo类的speed值。
另一种(可以说是更好的)方法是使用ScriptableObjectInstaller而不是MonoInstaller,ScriptableObjectInstaller具有额外的优势,您可以在运行时更改您的设置,并在停止运行时自动保存这些更改。详情请见“Scriptable Object 安装器”章节。

对象图验证

概览
使用DI框架设置绑定时的工作流程通常如下:

  • 在代码中添加一些绑定
  • 执行你的应用程序
  • 观察一堆与DI相关的异常
  • 修改绑定以解决问题
  • 重复
    这适用于小型项目,但随着项目复杂性的增加,这通常是一个单调乏味的过程。如果应用程序的启动时间特别糟糕,或者异常仅发生在运行时各个点的工厂,则问题会变得更严重。使用一些工具来分析您的对象图并告诉您所有缺少的绑定的确切位置,而无需启动整个应用程序试是非常好的。

你可以通过Edit -> Zenject -> Validate Current Scene进行验证,或者在打开要验证场景的情况下按Shift+Alt+V进行验证,这将会验证当前场景的所有安装器。然后遍历对象图并验证是否可以找到所有绑定(而实际上不会实例化任何绑定)。换句话说,它执行正常启动过程的“干运行”。在引擎盖下,这可以通过在容器中存储虚拟对象来代替实际实例化类来实现。
或者,您可以执行菜单项Edit -> Zenject -> Validate Then Run或只是按下CTRL+SHIFT+R。这将验证您打开的场景,然后如果验证成功,它将开始运行。验证通常非常快,所以相较于点击“运行”按钮这可能是一个更好的选择,特别是当你的游戏启动时间很长的时候。
请注意,这还将包括工厂和内存池,这非常有用,因为这些错误可能在启动后的某个时间才会被捕获。
有几点需要注意:

  • 没有执行实际的逻辑代码 - 只调用安装绑定。这意味着如果除了绑定命令之外的安装器中有逻辑,那么这些逻辑也会执行,并且在运行验证时可能会导致问题(如果该逻辑要求容器返回实际值)
  • null值将会被注入实际实例化的依赖项中,例如安装器(绑定内容的关键字)
    您可能希望在验证模式下注入一些类。在这种情况下,您可以用它们标记它们[ZenjectAllowDuringValidation]
    另请注意,某些验证行为可在zenjectsettings中配置

自定义验证

如果要添加自己的验证逻辑,只需将一个类继承IValidatable即可完成此操作。执行此操作后,只要您的类在某个安装器中绑定,它将在验证期间实例化,然后Validate()方法将被调用。但请注意,它所具有的任何依赖项将被注入为null(除非标记为[ZenjectAllowDuringValidation]属性)。

如果您希望验证失败,您可以在Validate方法内部抛出异常,或者只是将信息记录到控制台。自定义validatable中出现的一个常见问题是实例化无法验证的类型。通过在验证期间实例化它们,它将确保可以解决所有依赖关系。

例如,如果您创建一个直接使用Container.Instantiate<Foo>()实例化类型的自定义工厂,则Foo不会被验证,因此在运行时之前您不会发现它是否缺少某些依赖项。但是,您可以通过让工厂实现IValidatable然后在Validate()方法内部调用Container.Instantiate<Foo>()来解决此问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345