C# 尼尼特。将所有接口绑定到singleton作用域中的同一类

C# 尼尼特。将所有接口绑定到singleton作用域中的同一类,c#,dependency-injection,singleton,ninject,C#,Dependency Injection,Singleton,Ninject,我希望一个类既是一个对象,它提供关于后端的信息,也是一个类,当服务器停机时后端会通知它(例如ZooKeeper或WCF)。 问题是,当我将同一个类绑定到singleton范围中的两个不同接口时,Ninject会创建两个实例或抛出一个错误,具体取决于我的操作方式 以下示例必须打印相同的Guid,并且必须绑定所有接口 例如: Program.cs using System; using Ninject; using Ninject.Modules; namespace ConsoleApplica

我希望一个类既是一个对象,它提供关于后端的信息,也是一个类,当服务器停机时后端会通知它(例如ZooKeeper或WCF)。 问题是,当我将同一个类绑定到singleton范围中的两个不同接口时,Ninject会创建两个实例或抛出一个错误,具体取决于我的操作方式

以下示例必须打印相同的Guid,并且必须绑定所有接口

例如:

Program.cs

using System;
using Ninject;
using Ninject.Modules;

namespace ConsoleApplication1
{
    static class Program
    {
        static void Main(string[] args)
        {
            IKernel kernel = new StandardKernel();
            kernel.Load(new INinjectModule[] { new Bindings() });
            Console.WriteLine("First interface");
            var i1 = kernel.Get<IState>();
            i1.Inform();
            Console.WriteLine("Second interface");
            var i2 = kernel.Get<IListener>();
            i2.Send();
            Console.ReadKey();
        }
    }
}
namespace ConsoleApplication1
{
    public interface IListener
    {
        void Send();
    }
}
namespace ConsoleApplication1
{
    public interface IState
    {
        void Inform();
    }
}
IState.cs

using System;
using Ninject;
using Ninject.Modules;

namespace ConsoleApplication1
{
    static class Program
    {
        static void Main(string[] args)
        {
            IKernel kernel = new StandardKernel();
            kernel.Load(new INinjectModule[] { new Bindings() });
            Console.WriteLine("First interface");
            var i1 = kernel.Get<IState>();
            i1.Inform();
            Console.WriteLine("Second interface");
            var i2 = kernel.Get<IListener>();
            i2.Send();
            Console.ReadKey();
        }
    }
}
namespace ConsoleApplication1
{
    public interface IListener
    {
        void Send();
    }
}
namespace ConsoleApplication1
{
    public interface IState
    {
        void Inform();
    }
}
StateClass.cs 使用制度

namespace ConsoleApplication1
{
    public class StateClass : IState, IListener
    {
        private readonly String _seed;
        public StateClass()
        {
            _seed = Guid.NewGuid().ToString();
        }
        public void Send()
        {
            Console.WriteLine(_seed);
        }

        public void Inform()
        {
            Console.WriteLine(_seed);
        }
    }
}
Bindings.cs-Version 1在本例中,如果对代码进行了注释,那么一切都可以工作。问题是我事先不知道如果一个类推动IState接口,那么它也将IListener接口:

using Ninject.Modules;
using Ninject.Extensions.Conventions;

namespace ConsoleApplication1
{
    class Bindings : NinjectModule
    {
        public override void Load()
        {
            Kernel.Bind(x => x
                .FromAssemblyContaining<IState>()
                .SelectAllClasses()
                .InheritedFrom<IState>()
                .BindAllInterfaces()
                .Configure(y => y.InSingletonScope()));
            //uncomment the following binding to see an exception
            //problem is we dont know this in advance
            //Kernel.Bind(x => x
            //    .FromAssemblyContaining<IListener>()
            //    .SelectAllClasses()
            //    .InheritedFrom<IListener>()
            //    .BindAllInterfaces()
            //    .Configure(y => y.InSingletonScope()));
        }
    }
}
使用Ninject.Modules;
使用Ninject.Extensions.Conventions;
命名空间控制台应用程序1
{
类绑定:NinjectModule
{
公共覆盖无效负载()
{
Bind(x=>x
.FromAssemblyContaining()
.SelectAllClasses()
.继承自()
.BindAllInterfaces()
.Configure(y=>y.InSingletonScope());
//取消注释以下绑定以查看异常
//问题是我们事先不知道这一点
//Bind(x=>x
//.FromAssemblyContaining()
//.SelectAllClasses()
//.继承自()
//.BindAllInterfaces()
//.Configure(y=>y.InSingletonScope());
}
}
}
Bindings.cs-版本2-无例外,但应用程序打印不同的GUI:

using Ninject.Modules;
using Ninject.Extensions.Conventions;

    namespace ConsoleApplication1
    {
        class Bindings : NinjectModule
        {
            public override void Load()
            {
                Kernel.Bind<IListener>().To<StateClass>().InSingletonScope();
                Kernel.Bind<IState>().To<StateClass>().InSingletonScope();
            }
        }
    }
使用Ninject.Modules;
使用Ninject.Extensions.Conventions;
命名空间控制台应用程序1
{
类绑定:NinjectModule
{
公共覆盖无效负载()
{
Kernel.Bind().To().InSingletonScope();
Kernel.Bind().To().InSingletonScope();
}
}
}

因此,我认为在您的模块中,您必须告诉Ninject两个接口使用相同的对象。如果没有,Ninject将始终假定每个接口都有自己的单例

class Bindings : NinjectModule
{
    public override void Load()
    {
        Kernel.Bind<StateClass>().ToSelf().InSingletonScope();
        Kernel.Bind<IListener>().ToMethod(ctx => ctx.Kernel.Get<StateClass>());
        Kernel.Bind<IState>().ToMethod(ctx => ctx.Kernel.Get<StateClass>());
    }
}
类绑定:Ninject模块
{
公共覆盖无效负载()
{
Kernel.Bind().ToSelf().InSingletonScope();
Kernel.Bind().ToMethod(ctx=>ctx.Kernel.Get());
Kernel.Bind().ToMethod(ctx=>ctx.Kernel.Get());
}
}

Ninject.Conventions部分如何,当一个人的目标是插件基础设施时?我认为这些约定将始终单独处理每个接口;换句话说,为每个接口创建一个单例,不管它是由什么实现的。如果您真的希望它是可插拔的,我认为您需要另一层抽象——创建一个单独的代理类(作为单例),它将保存IListener实现和IState实现都需要访问的任何数据(本例中的Guid)。这样,框架对接口的实现是不可知的。