【问题标题】:Binding singleton to multiple services in Ninject在 Ninject 中将单例绑定到多个服务
【发布时间】:2010-06-30 09:32:03
【问题描述】:

我有一个问题似乎与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 实例。

这会导致解析Service时出现循环依赖异常。

这是设计使然,还是错误?

【问题讨论】:

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


【解决方案1】:

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


如果您希望共享单例,您需要将您的第二个Bind 更改为:

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

Re循环引用和混淆等。内部隐式自绑定将为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 - 该示例将具有正确的顺序,但根据我对源代码的阅读以及它生成隐式类自绑定的方式,上述示例是有意义的。

【讨论】:

  • 这实际上会在我的场景中导致堆栈溢出。当我有时间时,我会尝试隔离问题并发布我的场景的简约示例。
  • 嘿,我似乎错误地应用了你的第一个建议——我使用了 Get 而不是 Get。哦。 ;)
  • 顺便说一句,如果您发现单例的多个绑定有任何古怪之处,请阅读我刚刚坚持的问题 - Ninject 中的处理方式有一些改进
【解决方案2】:

顺便说一句,忍者3allows this syntax:

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

或者,类似地:

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

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

【讨论】:

  • 这是要走的路,但在最初提出问题时可能不可用。
  • @BatteryBackupUnit:关于您的编辑:对我来说,这看起来不像有效的 C# 语法。您能否澄清一下,或者可能将其添加为您自己的答案?
  • 对不起,我想是有点太急切了。对于 Bind,有一个重载 Bind(params Type[] services),它接受(几乎)任意数量的类型。 Bind&lt;IX, IFoo&gt; 最多有 4 种类型。因此,如果您有超过 4 种类型或使用反射来获取类型,则另一个重载是有益的。您能否用更好的“措辞”将其添加到您自己的答案中?恕我直言,这将使答案完整。
【解决方案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;
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多