在Ninject中将单例绑定到多个服务

时间:2010-06-30 09:32:03

标签: .net inversion-of-control ninject ninject-2

我遇到的问题与http://markmail.org/message/6rlrzkgyx3pspmnf中描述的问题非常相似,如果您使用不同的服务类型访问它,实际上创建的单个实例不仅仅是单个实例。

我正在使用最新版本的Ninject 2 for Compact Framework,我遇到的确切问题是,如果我将相同的提供程序方法绑定到:

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

如果我将其解析为IService和Service,它似乎正在创建2个服务实例。

这在解析Service时会导致循环依赖性异常。

这是设计还是错误?

3 个答案:

答案 0 :(得分:11)

在V3中,最终有一个解决方案,形式为new overloads on Bind,见this related: question


如果您希望共享单身人士,则需要将第二个Bind更改为:

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

重复循环引用和混淆等。内部隐式自绑定将为Service添加隐式绑定注册。你应该发布例外。

编辑:重新评论。如果你这样做:

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 - 该示例将具有正确的顺序,但上面的那个基于我对源的读取以及它生成隐式类自绑定的方式是有意义的。

答案 1 :(得分:5)

顺便说一句,Ninject 3 allows this syntax

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

或者,类似地:

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

如果您有许多服务,或者如果您在运行时动态发现服务(后者可以直接将params - 样式参数作为数组传递),后一种方法可以更好地工作。

答案 2 :(得分: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;
}