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

发布于 2024-09-07 10:28:08 字数 603 浏览 0 评论 0原文

我遇到的问题似乎与 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时出现循环依赖异常。

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

I have a problem which seems very similar to the one described in http://markmail.org/message/6rlrzkgyx3pspmnf which is about the singleton actually creating more than a single instance if you're accessing it using different service types.

I'm using the latest release of Ninject 2 for Compact Framework and the exact issue I'm having is that if I bind the same provider method to:

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

It seems to be creating 2 instances of Service if I resolve both as IService and Service.

This causes a circular dependency exception when resolving Service.

Is this by design, or is it a bug?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

在风中等你 2024-09-14 10:28:08

在 V3 中,终于有一个解决方案,形式为 Bind 上的新重载,请参阅 此相关:问题


如果你想共享单例,你需要将第二个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 得到解析时,不会生成隐式类自绑定 - 它使用现有的类自绑定。

这里还有另一个问题最近几周,有人在做这类事情,但遇到了 IInitialized 的问题 - 该示例将具有正确的顺序,但根据我对源代码的阅读以及它生成的方式,上面的顺序是有意义的隐式类自绑定。

In V3, there is finally a solution for this in the shape of new overloads on Bind, see this related: question.


If you want the singleton to be shared, you need to change your second Bind to:

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

Re circular references and confusion etc. Internally the implicit self-binding will add an implicit binding registration for Service. You should post the exception.

EDIT: Re your comment. If you do it like this:

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

Then no implicit Class Self Binding gets generated when IService gets Resolved - it uses the existing one.

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 - that example would have the correct ordering but the one above makes sense based on my reading of the source and the way in which it generates the implicit class self-bindings.

凉薄对峙 2024-09-14 10:28:08

顺便说一下,Ninject 3 允许这种语法

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

或者,类似地:

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

如果您有许多服务,或者如果您在运行时动态发现服务(您可以将 params 样式的参数传递为直接数组)。

By the way, Ninject 3 allows this syntax:

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

Or, similarly:

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

This latter approach works better if you have many services, or if you discovered the services dynamically at runtime (you can pass the params-style arguments as an array directly).

昔梦 2024-09-14 10:28:08

我们在项目中使用了 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;
}

We used Ruben's method in our project, but found that it wasn't intuitive why you were going back to the Kernel in your binding. I created an extension method and helper class (below) so you can do this:

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

That seemed to express the intent more clearly to me.

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文