web-dev-qa-db-ja.com

Ninjectシングルトンをセットアップする方法

MyFacadeでパラメーターを挿入したクラス(Ninject)があります。

_class MyFacade
{
    IDemoInterface demo;

    public MyFacade(IDemoInterface demo)
    {
        this.demo = demo;
    }

    public void MyMethod()
    {
        Console.WriteLine(demo.GetInfo());
    }
} 
_

もちろん、パラメータの適切な実装を挿入するには、Ninjectを設定する必要があります(IDemoInterface

kernel.Get<MyFacade>();を実行することで、何も設定せずにMyFacadeオブジェクトをインスタンス化できることはわかっています。現在、私のファサードにはインターフェイスがありません(これが私の唯一の実装であるため、標準の提案用にインターフェイスを追加する可能性があります)

このファサードをシングルントンにしたい場合は、2つの方法を知っています。空のコンストラクターを作成し、このkernel.Get<IDemoInterface>();を実行するか、次のようにNinjectを設定してパラメーターを渡します。kernel.Bind<MyFacade>().To<MyFacade>().InSingletonScope();

2つ目はより良いアプローチに見えますが、シングルトン方式でセットアップする他の方法を知っていますか?

14
Jaider

バインディングを設定するときは、依存関係をバインドする必要があります。コンストラクターでkernel.Get<T>()を実行するのではなく、バインディングで依存関係を設定することをお勧めします。 IOCを使用しているので、使用しているフレームワークを活用してインジェクションを実行します。

2番目のバインディングの例では、不足しているのはIDemoInterfaceでのバインディングです。バインディングは次のようになります。

//bind the dependency to the implementation.
kernel.Bind<IDemoInterface>().To<DemoInterface>();
//since you bound your dependency, ninject should now have 
// all the dependencies required to instantiate your `MyFacade` object.
kernel.Bind<MyFacade>.To<MyFacade>().InSingletonScope(); 
26
Joe Brunscheon

コンテナがInSingletonScope()を使用してシングルトンのライフサイクルを管理することを望まないが、それでもコンテナを注入したい場合は、2つの方法が考えられます。ニーズに合ったものを選択してください。次のISingleton(インターフェイスに名前を付ける)の実装を検討してください。

_public class ConcreteSingleton : ISingleton
{
    private static readonly Lazy<ConcreteSingleton> _instance = new Lazy<ConcreteSingleton>(() => new ConcreteSingleton());

    private ConcreteSingleton() { }

    public static ConcreteSingleton Instance
    {
        get
        {
            return _instance.Value;
        }
    }
}
_
  1. シングルトンクラスを変更してaGetInstance(...)method

    このメソッド(私の推奨するアプローチ)では、シングルトンが初めて初期化されるときにのみ、毎回kernel.Inject(instance)を呼び出すことはありません。 ConcreteSingletonクラスに次のメソッドを追加します。

    _public static ConcreteSingleton GetInstance(IKernel kernelForInjection)
    {
        if (_instance.IsValueCreated == false)
        {
            kernelForInjection.Inject(_instance.Value);
        }
    
        return _instance.Value;
    }
    _

    そして、このバインディングを使用します。

    _kernel.Bind<ISingleton>().ToMethod(c => ConcreteSingleton.GetInstance(c.Kernel));
    _

    パブリックコンストラクターを持たないが、ファサードを効率的に注入できるようにするという望ましい動作を実現します。

  2. ISingletonインスタンスが要求されるたびにインジェクションを実行します

    何らかの理由でConcreteSingletonの変更が許可されていない場合:このアプローチでは、プロバイダーでシングルトンの作成をラップして、インスタンスが初めて作成されたときにのみ効率的にインスタンスを注入します。プロバイダー自体はシングルトンとして登録する必要があることに注意することが重要です。

    _internal class ConcreteSingletonProvider : Provider<ISingleton>
    {
        public IKernel Kernel { get; set; }
    
        //Just a wrapper
        private readonly Lazy<ISingleton> _lazy = new Lazy<ISingleton>(() => ConcreteSingleton.Instance);
    
        public ConcreteSingletonProvider(IKernel kernel)
        {
            Kernel = kernel;
        }
    
        protected override ISingleton CreateInstance(IContext context)
        {
            if (_lazy.IsValueCreated == false)
            {
                Kernel.Inject(ConcreteSingleton.Instance);
            }
            return _lazy.Value;
        }
    }
    _

    そして、バインディングは次のようになります。

    _kernel.Bind<ISingleton>().ToProvider<ConcreteSingletonProvider>();
    kernel.Bind<ConcreteSingletonProvider>().ToSelf().InSingletonScope();
    _

    この 要点 には、上記のアプローチの完全な作業サンプルがあります。

お役に立てば幸いです。

5
cvbarros