2010-02-25 40 views
4

我正在使用Ninject 1.0,並希望能夠將惰性初始化委託注入到構造函數中。因此,考慮到通用委託定義:使用Ninject的惰性泛型委託初始化

public delegate T LazyGet<T>(); 

我只是想這種結合IKernel.Get(),這樣我可以通過一個懶惰的吸氣劑置入構造,例如

public class Foo 
{ 
    readonly LazyGet<Bar> getBar; 

    public Foo(LazyGet<Bar> getBar) 
    { 
     this.getBar = getBar; 
    } 
} 

但是,我不能簡單地調用Bind<LazyGet<T>>(),因爲它是一個開放的泛型類型。我需要這是一個開放的泛型,所以我不必綁定所有不同的懶惰獲取顯式類型。在上面的例子中,應該可以動態地創建一個通用代理,調用IKernel.Get<T>()

Ninject 1.0如何實現?

+0

注入的依賴是顯式的指定偷懶,國際海事組織,一漏抽象。有關詳細信息,請參閱此處:http://blog.ploeh.dk/2010/01/20/RebuttalConstructorOverinjectionAntipattern.aspx – 2010-02-25 13:55:38

+0

我知道,但我正在轉換一個現有的代碼庫,其中包含很多高度耦合的靜態代碼。這只是擺脫所有靜態類的第一步。 – 2010-02-25 13:58:21

+0

足夠公平:)無論如何,我從不意味着我的評論是不屑一顧的。然而,我指出的這篇文章確實提供了一個明確實施懶惰作爲裝飾者的出路。我只是不想提供這個答案,因爲你可能會從其他人得到一個適當的Ninject答案:) – 2010-02-25 14:02:24

回答

0

不完全明白這個問題,但你能用反射嗎?喜歡的東西:

// the type of T you want to use 
Type bindType; 
// the kernel you want to use 
IKernel k; 

// note - not compile tested 
MethodInfo openGet = typeof(IKernel).GetMethod("Get`1"); 
MethodInfo constGet = openGet.MakeGenericMethod(bindType); 

Type delegateType = typeof(LazyGet<>).MakeGenericType(bindType); 
Delegate lazyGet = Delegate.CreateDelegate(delegateType, k, constGet); 

使用會lazyGet讓你做你想要什麼?請注意,如果在編譯上下文中未知bindType,則可能必須通過反射來調用Foo類。

+0

感謝代碼,但它是「裸體」的 - t顯示這是如何在Ninject中註冊的。我可以像編寫代碼一樣輕鬆地編寫代碼,但是如何告訴Ninject將其綁定,以便當它創建一個採用懶惰委託的類型的實例時,它將它綁定到它自己的Get方法? 我在做什麼似乎很清楚:我想將參數綁定到Ninject自己的Get方法,以便當對象請求該類型的實例時,它會調用Ninject的Get。 – 2010-04-17 15:26:35

0

我相當確定唯一的方法來做到這一點(沒有一些髒的反射代碼)是綁定你的委託類型參數。這意味着您需要爲每個使用的個人類型完成。你可以使用BindingGenerator來批量執行此操作,但它可能會有點難看。

如果有更好的解決方案(一個乾淨的解決方案),我很樂意聽到它,因爲我時不時碰到這個問題。

0

another similar question我回答:

public class Module : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind(typeof(Lazy<>)).ToMethod(ctx => 
       GetType() 
        .GetMethod("GetLazyProvider", BindingFlags.Instance | BindingFlags.NonPublic) 
        .MakeGenericMethod(ctx.GenericArguments[0]) 
        .Invoke(this, new object[] { ctx.Kernel })); 
    } 

    protected Lazy<T> GetLazyProvider<T>(IKernel kernel) 
    { 
     return new Lazy<T>(() => kernel.Get<T>()); 
    } 
}