2010-06-30 73 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