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自定義了一個這種方式的綁定方法。上面的代碼相當(dāng)于:
Container.BindInterfacesAndSelfTo<Foo>().AsSingle();
現(xiàn)在,我們可以添加或者刪除Foo的接口,而安裝器不用修改。
在某些情況下,你可能只需要綁定的接口,并保持Foo對其他類隱藏。在這種情況下,您可以使用BindInterfacesTo方法:
Container.BindInterfacesTo<Foo>().AsSingle()
在該例中,相當(dāng)于:
Container.Bind(typeof(IInitializable), typeof(IDisposable)).To<Foo>().AsSingle();
使用Unity的檢視面板配置設(shè)置
將大部分代碼編寫為普通C#類而不是MonoBehaviour的一個后果是,您無法使用檢查面板中配置數(shù)據(jù)。但是,您可以通過在Zenject中使用下面的方式來實現(xiàn)此功能:
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);
}
}
現(xiàn)在,如果我們運行場景,我們可以在檢視面板中實時調(diào)整Foo類的speed值。
另一種(可以說是更好的)方法是使用ScriptableObjectInstaller而不是MonoInstaller,ScriptableObjectInstaller具有額外的優(yōu)勢,您可以在運行時更改您的設(shè)置,并在停止運行時自動保存這些更改。詳情請見“Scriptable Object 安裝器”章節(jié)。
對象圖驗證
概覽
使用DI框架設(shè)置綁定時的工作流程通常如下:
- 在代碼中添加一些綁定
- 執(zhí)行你的應(yīng)用程序
- 觀察一堆與DI相關(guān)的異常
- 修改綁定以解決問題
- 重復(fù)
這適用于小型項目,但隨著項目復(fù)雜性的增加,這通常是一個單調(diào)乏味的過程。如果應(yīng)用程序的啟動時間特別糟糕,或者異常僅發(fā)生在運行時各個點的工廠,則問題會變得更嚴重。使用一些工具來分析您的對象圖并告訴您所有缺少的綁定的確切位置,而無需啟動整個應(yīng)用程序試是非常好的。
你可以通過Edit -> Zenject -> Validate Current Scene進行驗證,或者在打開要驗證場景的情況下按Shift+Alt+V進行驗證,這將會驗證當(dāng)前場景的所有安裝器。然后遍歷對象圖并驗證是否可以找到所有綁定(而實際上不會實例化任何綁定)。換句話說,它執(zhí)行正常啟動過程的“干運行”。在引擎蓋下,這可以通過在容器中存儲虛擬對象來代替實際實例化類來實現(xiàn)。
或者,您可以執(zhí)行菜單項Edit -> Zenject -> Validate Then Run或只是按下CTRL+SHIFT+R。這將驗證您打開的場景,然后如果驗證成功,它將開始運行。驗證通常非常快,所以相較于點擊“運行”按鈕這可能是一個更好的選擇,特別是當(dāng)你的游戲啟動時間很長的時候。
請注意,這還將包括工廠和內(nèi)存池,這非常有用,因為這些錯誤可能在啟動后的某個時間才會被捕獲。
有幾點需要注意:
- 沒有執(zhí)行實際的邏輯代碼 - 只調(diào)用安裝綁定。這意味著如果除了綁定命令之外的安裝器中有邏輯,那么這些邏輯也會執(zhí)行,并且在運行驗證時可能會導(dǎo)致問題(如果該邏輯要求容器返回實際值)
- null值將會被注入實際實例化的依賴項中,例如安裝器(綁定內(nèi)容的關(guān)鍵字)
您可能希望在驗證模式下注入一些類。在這種情況下,您可以用它們標(biāo)記它們[ZenjectAllowDuringValidation]。
另請注意,某些驗證行為可在zenjectsettings中配置
自定義驗證
如果要添加自己的驗證邏輯,只需將一個類繼承IValidatable即可完成此操作。執(zhí)行此操作后,只要您的類在某個安裝器中綁定,它將在驗證期間實例化,然后Validate()方法將被調(diào)用。但請注意,它所具有的任何依賴項將被注入為null(除非標(biāo)記為[ZenjectAllowDuringValidation]屬性)。
如果您希望驗證失敗,您可以在Validate方法內(nèi)部拋出異常,或者只是將信息記錄到控制臺。自定義validatable中出現(xiàn)的一個常見問題是實例化無法驗證的類型。通過在驗證期間實例化它們,它將確保可以解決所有依賴關(guān)系。
例如,如果您創(chuàng)建一個直接使用Container.Instantiate<Foo>()實例化類型的自定義工廠,則Foo不會被驗證,因此在運行時之前您不會發(fā)現(xiàn)它是否缺少某些依賴項。但是,您可以通過讓工廠實現(xiàn)IValidatable然后在Validate()方法內(nèi)部調(diào)用Container.Instantiate<Foo>()來解決此問題。