2011-03-10 88 views
2

我主要使用Ninject的基本功能。因此,這個問題可能太明顯了。如果是這樣,請原諒。不管怎麼說,我有一個模塊中的以下內容:Ninject上下文綁定

Bind<Double>().ToConstant(TimeSpan.FromSeconds(10).TotalMilliseconds).Only(When.Context.Target.Name.AsString=="A"); 
Bind<Double>().ToConstant(TimeSpan.FromHours(1).TotalMilliseconds).Only(When.Context.Target.Name.AsString=="B"); 
Bind<Double>().ToConstant(TimeSpan.FromMinutes(5).TotalMilliseconds).Only(When.Context.Target.Name.AsString=="C"); 

現在的問題是,我該如何使用kernel.get<Double>()解析到,我想上面的綁定中的任何一個?

+0

參見http://stackoverflow.com/questions/2507881/contextual-bindings-with-ninject-2-0 – 2011-03-10 14:10:17

回答

9

首先,我們可以保留基於約定的綁定,意思是https://github.com/ninject/ninject.extensions.conventions(而不是像你在示例中那樣顯式硬連接綁定) - 我編輯了問題標題以反映這一點。

現在,回答你的實際問題。您似乎想要設置上下文綁定,以便能夠在不同的上下文中輸入適當的值。我建議,編輯一個更好的例子,你實際上正在努力實現可能會得到/得到你一個更好的答案。

第一個問題是您使用的是v1語法。這裏是你想在V2語法達到什麼樣的一個例子:

class ContextualBindingsExample 
{ 
    internal class A 
    { 
     public A(double x) 
     { 
      X = x; 
     } 

     public double X { get; private set; } 
    } 

    internal class B 
    { 
     public B(double y) 
     { 
      Y = y; 
     } 

     public double Y { get; private set; } 
    } 

    [Fact] 
    public static ContextualBindingAllowsOneToFilterWhenInjectingIntoRoots() 
    { 
     var k = new StandardKernel(); 
     k.Bind<double>().ToConstant(1).WhenInjectedInto<A>(); 
     k.Bind<double>().ToConstant(2).When(request => request.Target.Name == "y"); 
     Assert.Equal(k.Get<B>().Y, 2); 
     Assert.Equal(k.Get<A>().X, 1); 
    } 
} 

上述方法(試圖Get東西,你的條件狀況相一致),通常是你所需要的。如果沒有,你可以按如下方式合成它。注意,這不是一件正常的事情,如果你想這樣做,你可能做錯了事情。

您可能還在尋找的方法是將東西存儲在容器中,然後根據過濾條件將其拉出。這是這樣的:

[Fact] 
    public static void BindingMetadataShouldAllowContextualFiltering() 
    { 
     var k = new StandardKernel(); 
     k.Bind<double>().ToConstant(2).WithMetadata("a", "b"); 
     k.Bind<double>().ToConstant(30).WithMetadata("b", 2); 
     Assert.Equal(k.Get<double>(metadata => metadata.Get<string>("a") == "b"), 2); 
     Assert.Equal(k.Get<double>(metadata => metadata.Get<int>("b") == 2), 30); 
    } 

需要注意的是,這通常不是個好主意,但同樣,一個更好的問題將讓你更好更上下文答案有...

現在,我建議閱讀@Mark Seemann的最高評價答案,以獲得關鍵原則,這樣您就不會在雜草中結束試圖瞭解低級別DI工具的技巧!

編輯:請注意,https://github.com/ninject/ninject/wiki/Contextual-Binding已顯著更新,因爲這個問題(和答案),其中書面

+0

非常感謝。你不僅給出了關於設計的非常有建設性的暗示,而且還回答了我的實際問題。我認爲,即使這不是一個有用的選擇,至少如果有人想以正確的方式使用它,他們會發現你的例子有用。對此,我真的非常感激!關於基於分流的綁定我正在反思我從ninject wiki中讀到的內容https://github.com/ninject/ninject/wiki/Conventions-Based-Binding雖然可能我誤解了。 – amirmonshi 2011-03-10 13:57:26

+1

@amirmonshi:謝謝你的答覆和跟進。現在你已經指出了這一點,難怪你會稱之爲基於約定的綁定。文章將很快收到一些工作 - 正如它所指出的那樣,它有點困惑 - 對於我來說,有一些約定(通常是基於名稱的CoC la Ruby)與上下文相關(即具有屬性和其他更豐富的上下文,關注靜態信息)。我認爲其他一些文章涵蓋了上下文綁定。希望我能儘快解決,我可以消除一些混亂。 – 2011-03-10 14:08:06

+0

@amirmonshi:我也編輯了一些對條件綁定的引用,並用Contextual取代。這就是我用術語來玩的快速和鬆散。並且不要忘記關注我發佈在 – 2011-03-10 14:14:02

6

雖然這樣的配置可能會起作用,但它特別脆弱,會導致難以理解的代碼和難以理解的DI配置。約定優於配置是好的,但不要嘗試注入其他任何東西而不是服務。 A double不是服務,而是價值。

以下是你可能要考慮其他三個方法:

  1. 定義一個或多個服務與懂得回報這些價值觀明確的名稱。例如:

    public interface ISystemClock 
    { 
        DateTime Now { get; } 
    } 
    

    您可以注入此類服務。

  2. 定義一個接口,用於應用程序的配置:

    public interface IMyAppsConfiguration 
    { 
        double Value1 { get; } 
        double Value2 { get; } 
        double Value3 { get; } 
    } 
    
  3. 註冊直接使用Ninject類。

什麼是最好的答案很難說,因爲你的問題沒有透露你實際上試圖注入什麼。你正試圖注入雙打,但這些雙打實際上代表什麼?

+0

+1爲好的提示:) – amirmonshi 2011-03-10 13:58:59

+0

重新格式化後,我能夠讀取它,這很好 - 我同意你的OP的具體示例中心點不是一個好主意+1! – 2011-03-10 16:44:37

+0

@Ruben:感謝+,並感謝重新格式化。我不知道如何將代碼包含在列表項中。現在我看到了4個額外的空間。你已經有我的+,所以我不能給你更多;-) – Steven 2011-03-10 18:19:44