Ways to setup a Ninject singleton

前端 未结 2 613
面向向阳花
面向向阳花 2021-02-07 13:46

I have a class (MyFacade) that I injected parameter(s) with Ninject:

class MyFacade
{
    IDemoInterface demo;

    public MyFacade(IDe         


        
2条回答
  •  情歌与酒
    2021-02-07 14:12

    If you do not want the container to manage the lifecycle of your singleton by using InSingletonScope(), but still wants it to get injected, I can think of 2 ways to go about it. Choose which one suits better to your needs. Consider the following ISingleton (name your interface) implementation:

    public class ConcreteSingleton : ISingleton
    {
        private static readonly Lazy _instance = new Lazy(() => new ConcreteSingleton());
    
        private ConcreteSingleton() { }
    
        public static ConcreteSingleton Instance
        {
            get
            {
                return _instance.Value;
            }
        }
    }
    
    1. Alter the singleton class to have a GetInstance(...) method

      In this method (my preferred approach), you won't be calling kernel.Inject(instance) each time, only for the first time the singleton is initialized. Adding the following method to your ConcreteSingleton class:

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

      And using this binding:

      kernel.Bind().ToMethod(c => ConcreteSingleton.GetInstance(c.Kernel));
      

      Will achieve the desired behavior of not having a public constructor but enabling your facade to be efficiently injected.

    2. Perform injection each time the ISingleton instance is requested

      If by any reason you are not allowed to modify your ConcreteSingleton: This approach will wrap the singleton creation in a provider to efficiently inject the instance only for the first time it is created. It is important to note that the provider itself must be registered as a singleton.

      internal class ConcreteSingletonProvider : Provider
      {
          public IKernel Kernel { get; set; }
      
          //Just a wrapper
          private readonly Lazy _lazy = new Lazy(() => 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;
          }
      }
      

      And your bindings should be like this:

      kernel.Bind().ToProvider();
      kernel.Bind().ToSelf().InSingletonScope();
      

      This gist has a complete working sample for the above approach.

    Hope that helps!

提交回复
热议问题