Zenject框架(十三)

使用LazyInject <>進行即時解析(Just-In-Time Resolving Using LazyInject<>)

在某些情況下需要在啟動后延遲創(chuàng)建某些依賴項,您可以使用LazyInject <>構造來實現(xiàn)。

比如,假設有這樣一個腳本:

public class Foo
{
    public void Run()
    {
        ...
    }
}

public class Bar
{
    Foo _foo;

    public Bar(Foo foo)
    {
        _foo = foo;
    }

    public void Run()
    {
        _foo.Run();
    }
}

public class TestInstaller : MonoInstaller<TestInstaller>
{
    public override void InstallBindings()
    {
        Container.Bind<Foo>().AsSingle();
        Container.Bind<Bar>().AsSingle();
    }
}

假設我們只想在真正使用時才創(chuàng)建一個Foo的實例(也就是調(diào)用Bar.Run方法時)。 如上所述,即使從未調(diào)用過Bar.Run,每次創(chuàng)建Bar``時都會創(chuàng)建Foo。 我們可以通過將Bar```更改為以下內(nèi)容來解決此問題:

public class Bar
{
    LazyInject<Foo> _foo;

    public Bar(LazyInject<Foo> foo)
    {
        _foo = foo;
    }

    public void Run()
    {
        _foo.Value.Run();
    }
}

現(xiàn)在,通過使用LazyInject <>,直到第一次調(diào)用Bar.Run時才會創(chuàng)建Foo類的實例,之后,將會使用同個實例

請注意,這兩種情況下安裝器保持不變。任何注入依賴項都可以通過使用LazyInject <>變?yōu)檠舆t。

非泛型綁定(Non Generic bindings)

在某些情況下,您可能不知道要在編譯時綁定的確切類型。 在這些情況下,您可以使用Bind方法的重載,該方法采用System.Type值而不是泛型參數(shù)。

\\這兩行結果形同
Container.Bind(typeof(Foo));
Container.Bind<Foo>();

注意,使用非泛型綁定時,可以傳遞多個參數(shù):

Container.Bind(typeof(Foo), typeof(Bar), typeof(Qux)).AsSingle();

// 上面的一行等同于下面的三行:
Container.Bind<Foo>().AsSingle();
Container.Bind<Bar>().AsSingle();
Container.Bind<Qux>().AsSingle();

對于To方法同樣適用:

Container.Bind<IFoo>().To(typeof(Foo), typeof(Bar)).AsSingle();

// 上面的一行等同于下面的兩行:
Container.Bind<IFoo>().To<Foo>().AsSingle();
Container.Bind<IFoo>().To<Bar>().AsSingle();

或者,兩者混合:

Container.Bind(typeof(IFoo), typeof(IBar)).To(typeof(Foo1), typeof(Foo2)).AsSingle();

// 上面一行等同于下面幾行:
Container.Bind<IFoo>().To<Foo>().AsSingle();
Container.Bind<IFoo>().To<Bar>().AsSingle();
Container.Bind<IBar>().To<Foo>().AsSingle();
Container.Bind<IBar>().To<Bar>().AsSingle();

當您有一個類實現(xiàn)多個接口時,這可能特別有用:

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

雖然在這個特定的例子中已經(jīng)存在了內(nèi)置的快捷方法:

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

基于約定的綁定(Convention Based Binding)

基于約定的綁定可以在以下任何一種情況下派上用場:

  • 您想定義一個命名約定,該約定確定類如何綁定到容器(例如,使用前綴,后綴或正則表達式)
  • 您希望使用自定義屬性來確定類與容器的綁定方式
  • 您希望自動綁定在給定命名空間或程序集中實現(xiàn)給定接口的所有類

使用“convention over configuration”可以允許您定義一個框架,其他程序員可以使用該框架快速輕松地完成任務,而不必在安裝器中明確添加每個綁定。 這是Ruby on Rails,ASP.NET MVC等框架所遵循的理念。當然,這種方法既有優(yōu)點也有缺點。

除了不用向Bind()和To()方法提供類型列表外,它們以與非泛型綁定類似的方式指定,您可以使用Fluent API描述約定。 例如,要將IFoo綁定到在整個代碼庫中實現(xiàn)它的每個類:

Container.Bind<IFoo>().To(x => x.AllTypes().DerivingFrom<IFoo>());

注意,您也可以在Bind()方法中使用相同的Fluent API,您也可以在Bind()和To()中同時使用它。

有關更多示例,請參閱下面的示例部分。 完整格式如下:

x.InitialList().Conditional().AssemblySources()

這里:

  • InitialList = 用于綁定的初始類型列表。 此列表將由給定的條件進行過濾。 它可以是以下(相當自我解釋)方法之一:
    i.AllTypes
    ii.AllNonAbstractClasses
    iii.AllAbstractClasses
    iv.AllInterfaces
    v.AllClasses
  • Conditional = 要應用于InitialList給出的類型列表的過濾器。 請注意,您可以根據(jù)需要將所有這些鏈接在一起,并且它們將按順序應用于初始列表。 它可以是以下之一:
    i.DerivingFrom - 只匹配派生自T的類型
    ii.DerivingFromOrEqual - 只匹配派生自T類型或T類型
    iii.WithPrefix(value) - 只匹配名字以value開始的類型
    iv.WithSuffix(value) - 只匹配名字以value結尾的類型
    v.WithAttribute - 只匹配類以[T]特性修飾的類型
    vi.WithoutAttribute - 只匹配類沒有以[T]特性修飾的類型
    vii.WithAttributeWhere(predicate) - 僅匹配在類聲明之上具有屬性[T]的類型,并且在傳遞屬性時給定謂詞返回true。 這很有用,因此您可以使用賦予該屬性的數(shù)據(jù)來創(chuàng)建綁定
    viii.InNamespace(value)-只匹配在給定命名空間中的類型
    ix.InNamespaces(value1,value2,等)-只匹配在給定命名空間中的類型
    x.MatchingRegex(pattern) - 只匹配符合給定正則表達式的類型
    xi.Where(predicate) - 最后,您還可以通過傳入帶有Type參數(shù)的謂詞來添加任何類型的條件邏輯
  • AssemblySources = 填充InitialList時要搜索類型的程序集列表。 它可以是以下之一:
    i.FromAllAssemblies - 在所有加載的程序集中查找類型,未指定時默認該值
    ii.FromAssemblyContaining - 在包含[T]的程序集中查找類型
    iii.FromAssembliesContaining(type1, type2, ..) - 在包含[T]的程序集中查找類型
    iv.FromThisAssembly- 僅在要調(diào)用此方法的程序集中查找類型
    v.FromAssembly(assembly) - 僅在給定的程序集中查找類型
    vi.FromAssemblies(assembly1, assembly2, ...) - 僅在給定的程序集中查找類型
    vii.FromAssembliesWhere(predicate) - 在與給定謂詞匹配的所有程序集中查找類型

例子:

請注意,您可以將以下項任意組合在同一個綁定中。 另請注意,由于我們未在此處指定程序集,因此Zenject將在所有已加載的程序集中進行搜索。
1.將IFoo綁定到整個代碼庫中實現(xiàn)它的每個類:

Container.Bind<IFoo>().To(x => x.AllTypes().DerivingFrom<IFoo>());

注意,以下結果相同:

Container.Bind<IFoo>().To(x => x.AllNonAbstractTypes());

這是因為Zenject將跳過具體類型不是從基類型派生的任何綁定。 另請注意,在這種情況下,我們必須確保使用AllNonAbstractTypes而不僅僅是AllTypes,以確保我們不將IFoo綁定到自身

2.將接口綁定到在給定命名空間內(nèi)實現(xiàn)它的所有類

Container.Bind<IFoo>().To(x => x.AllTypes().DerivingFrom<IFoo>().InNamespace("MyGame.Foos"));

3.自動綁定IController每個具有后綴“Controller”的類(如ASP.NET MVC中所做的那樣):

Container.Bind<IController>().To(x => x.AllNonAbstractTypes().WithSuffix("Controller"));

你也可以使用MatchingRegex:

Container.Bind<IController>().To(x => x.AllNonAbstractTypes().MatchingRegex("Controller$"));

4.使用前綴“Widget”綁定所有類型并注入Foo

Container.Bind<object>().To(x => x.AllNonAbstractTypes().WithPrefix("Widget")).WhenInjectedInto<Foo>();

5.自動綁定給定命名空間中每種類型使用的接口

Container.Bind(x => x.AllInterfaces())
    .To(x => x.AllNonAbstractClasses().InNamespace("MyGame.Things"));

這相當于為名稱空間“MyGame.Things”中的每個類型調(diào)用Container.BindInterfacesTo <T>()。 這是有效的,因為如上所述,Zenject將跳過任何綁定,其中具體類型實際上不是從基類型派生的。 因此,即使我們使用AllInterfaces匹配每個加載的程序集中的每個單獨的接口,這也沒關系,因為它不會嘗試將接口綁定到不實現(xiàn)此接口的類型。

裝飾器綁定(Decorator Bindings)

見后續(xù)章節(jié)

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,652評論 1 32
  • ORA-00001: 違反唯一約束條件 (.) 錯誤說明:當在唯一索引所對應的列上鍵入重復值時,會觸發(fā)此異常。 O...
    我想起個好名字閱讀 5,964評論 0 9
  • http://liuxing.info/2017/06/30/Spring%20AMQP%E4%B8%AD%E6%...
    sherlock_6981閱讀 16,208評論 2 11
  • 機場大巴二號線,票價20首發(fā)5:30。到和興商廈站。
    橘紅歷程閱讀 112評論 0 0
  • UIButton 與 UITableView 的層級結構 繼承結構,屬于內(nèi)部的子控件結構 UIButton為:UI...
    iChuck閱讀 393評論 0 0

友情鏈接更多精彩內(nèi)容