2010-06-30 60 views
9

我有一個問題,看起來與http://markmail.org/message/6rlrzkgyx3pspmnf中描述的問題非常相似,如果您使用不同的服務類型訪問單個實例,實際創建的實例不止一個。在Ninject中將單例綁定到多個服務

我使用Ninject 2爲Compact Framework的,我有確切的問題的最新版本是,如果我同一個供應商的方法結合:

Func<Service> serviceCreator =() => new Service(false); 
kernel.Bind<IService>().ToMethod(serviceCreator).InSingletonScope(); 
kernel.Bind<Service>().ToMethod(serviceCreator).InSingletonScope(); 

這似乎是創建2個實例如果我將這兩個解決方案解決爲IService和服

解決服務時會導致循環依賴異常。

這是設計,還是一個錯誤?

+0

順便說一句我相信在Ninject的2.3和2.4版本中有一些不一致性正在清理,確保以這種方式重複使用的內容只會被激活和/或清理一次 – 2011-02-18 16:12:50

+0

請參閱V3特定的答案:http:///堆棧溢出。com/questions/10206049/ninject-is-it-it-possible-to-bind-different-interfaces-to-the-same-instance-of -ac- – 2012-09-12 08:53:00

+0

related:http://stackoverflow.com/questions/8303661/ninject-綁定接口到接口/ 8303826#comment16639462_8303826 – 2012-09-12 10:12:56

回答

11

在V3中,終於有一個解決方案,形狀爲new overloads on Bind,見this related: question


如果你想單身被共享,你需要改變你的第二個Bind到:

kernel.Bind<Service>().ToMethod(()=>kernel.Get<IService>()).InSingletonScope(); 

重新循環引用和混亂等內部隱含的自我約束力將增加一個隱式綁定服務註冊。你應該發佈例外。

編輯:重新發表您的評論。如果你不喜歡這樣寫道:

Func<Service> serviceCreator =() => new Service(false); 
kernel.Bind<Service>().ToMethod(serviceCreator).InSingletonScope(); 
kernel.Bind<IService>().ToMethod(()=>kernel.Get<Service>()).InSingletonScope(); 

然後當IService得到解決沒有隱含類自綁定都生成 - 它使用現有的一個。

There was another Q here on SO in recent weeks someone was doing this type of thing but was running into an issue with IInitializable - 該示例將具有正確的排序順序,但基於我對源代碼的閱讀和生成隱式類自綁定的方式,上面的順序是有意義的。

+0

這實際上導致我的方案中堆棧溢出。當我有時間時,我會嘗試隔離問題併發布我的場景的簡約示例。 – 2010-06-30 11:51:04

+0

@Michal:回覆編輯於 – 2010-06-30 22:03:46

+0

呵呵,好像我把你的第一個建議搞錯了 - 我用Get 代替Get 。 D'哦。 ;) – 2010-07-06 10:08:57

3

我們在我們的項目中使用了Ruben的方法,但發現它並不直觀,爲什麼你要回到綁定中的內核。我創建了一個擴展方法和輔助類(如下圖),所以你可以這樣做:

kernel.Bind<IService>().ToExisting().Singleton<Service>(); 

這似乎更清楚地表達意圖給我。

public static class DIExtensions 
{ 
    public static ToExistingSingletonSyntax<T> ToExisting<T>(this IBindingToSyntax<T> binding) 
    { 
     return new ToExistingSingletonSyntax<T>(binding); 
    } 
} 

// Had to create this intermediate class because we have two type parameters -- the interface and the implementation, 
// but we want the compiler to infer the interface type and we supply the implementation type. C# can't do that. 
public class ToExistingSingletonSyntax<T> 
{ 
    internal ToExistingSingletonSyntax(IBindingToSyntax<T> binding) 
    { 
     _binding = binding; 
    } 

    public IBindingNamedWithOrOnSyntax<T> Singleton<TImplementation>() where TImplementation : T 
    { 
     return _binding.ToMethod(ctx => ctx.Kernel.Get<TImplementation>()).InSingletonScope(); 
    } 


    private IBindingToSyntax<T> _binding; 
} 
+0

好的例子有一些改進。順便說一句,我相信有一個新的'綁定<> .Tobinding'或其他類似的東西,或者在一個擴展/在@Remo Gloor博客文章中提到一種類似於你的機制。 – 2011-07-31 21:24:33

+0

@RubenBartelink是正確的:https://github.com/ninject/ninject.extensions.contextpreservation – 2011-10-13 14:05:59

+0

我在前面的評論中暗指的鏈接http://www.planetgeek.ch/2011/12/30/new- ninject-3-0/ – 2012-09-12 08:33:36

5

順便說一句,Ninject 3 allows this syntax

kernel.Bind<IService, Service>().ToMethod(serviceCreator).InSingletonScope(); 

,或類似:

kernel.Bind(typeof(IService), typeof(Service)).ToMethod(serviceCreator).InSingletonScope(); 

這後一種方法效果更好,如果你有很多的服務,或者如果您發現該服務在運行時動態地(可以直接將params型參數作爲數組傳遞)。

+2

的功能和變化這是要走的路,但最初提出問題時可能無法使用。 – BatteryBackupUnit 2014-01-29 12:16:22

+0

@BatteryBackupUnit:關於你的編輯:這對我來說看起來不像是有效的C#語法。你能否澄清它,或者可能將它添加爲你自己的答案? – StriplingWarrior 2017-10-19 15:30:51

+1

對不起,我猜想有點太急了。對於綁定,有一個重載'綁定(params類型[]服務)'接受(幾乎)任何數量的類型。 「綁定」最多可以分爲4種類型。所以如果你有超過4種類型或者當你使用反射來獲得類型時,其他重載是有利的。你可以用一個更好的「措辭」把它加到你自己的答案上嗎?這將使答案完整恕我直言。 – BatteryBackupUnit 2017-10-20 06:00:17