Ninject:如何从工厂访问NamedScope的根对象

时间:2014-10-28 16:50:57

标签: dependency-injection ninject ninject-extensions

在我的应用程序中,我使用的是Ninject和NamedScopeExtension。对象图中更深层次的对象之一需要访问定义命名范围的根对象。在我看来,DefinesNamedScope()并不暗示InNamedScope(),而是在我请求根时创建了新的根对象。

示例:

using System;
using Ninject;
using Ninject.Extensions.NamedScope;
using Ninject.Syntax;

namespace NInjectNamedScope
{
    public interface IScopeRoot
    {
        Guid Guid { get; }
        void DoSomething();
    }

    public interface IFactory
    {
        Guid Guid { get; }
        IOther CreateOther();
    }

    public interface IOther
    {
        void SayHello();
    }

    internal class ScopeRoot : IScopeRoot
    {
        private readonly IFactory m_factory;
        private readonly IResolutionRoot m_kernel;
        public Guid Guid { get; private set; }

        public ScopeRoot(IFactory factory, IResolutionRoot kernel)
        {
            m_factory = factory;
            m_kernel = kernel;
            Guid = Guid.NewGuid();
        }

        public void DoSomething()
        {
            Console.WriteLine("ScopeRoot.DoSomething(): Entering");
            Console.WriteLine("ScopeRoot GUID: {0}", Guid);
            Console.WriteLine("IFactory  GUID: {0}", m_factory.Guid);
            var other = m_factory.CreateOther();
            Console.WriteLine("ScopeRoot.DoSomething(): Other created");
            other.SayHello();
            Console.WriteLine("ScopeRoot.DoSomething(): Exiting");
        }
    }

    internal class Factory : IFactory
    {
        private IResolutionRoot m_kernel;

        public Guid Guid { get; private set; }

        public Factory(IResolutionRoot kernel)
        {
            m_kernel = kernel;
            Guid = Guid.NewGuid();
        }
        public IOther CreateOther()
        {
            return m_kernel.Get<IOther>();
        }
    }

    internal class Other : IOther
    {
        private readonly IScopeRoot m_root;
        private readonly IFactory m_factory;

        public Other(IScopeRoot root, IFactory factory)
        {
            m_root = root;
            m_factory = factory;
        }

        public void SayHello()
        {
            Console.WriteLine("Other.SayHello(): Hello");
            Console.WriteLine("Our IScopeRoot has GUID: {0}", m_root.Guid);
            Console.WriteLine("Our IFactory has GUID:   {0}", m_factory.Guid);
        }
    }

    public class MainClass
    {
        public static void Main(string[] args)
        {
            var kernel = new StandardKernel();

            kernel.Bind<IScopeRoot>().To<ScopeRoot>().DefinesNamedScope("RootScope");
            kernel.Bind<IFactory>().To<Factory>().InNamedScope("RootScope");
            kernel.Bind<IOther>().To<Other>().InNamedScope("RootScope");

            var root = kernel.Get<IScopeRoot>();
            root.DoSomething();

            Console.ReadKey();
        }
    }
}

在此示例中,Other正在接收与root相同的Factory实例,但是创建了ScopeRoot的新实例,而不是注入定义了named的现有实例范围。

如何在工厂中访问指定范围的根目录?请注意,此示例已简化。实际上,范围根和工厂方法之间有几层对象,所以我不能简单地将this传递给工厂。

1 个答案:

答案 0 :(得分:2)

是的,你是对的,开箱即用的Ninject不能.DefinesNamedScope().InNamedScope()。除了可能是晚期&#34;创造&#34; (工厂,懒惰)无论如何都无法工作,因为它会产生循环依赖。

实现你想要的最简单的方法是创建一个&#34; root的根&#34; ...只是一个与ActualRoot绑定的类DefinesNamedScope()并得到一个IRootScope注入,再次与.InNamedScope()绑定。关于这一点的坏处是,您需要注入/ Get<> ActualRoot而不是IRootScope

据我记忆,你也可以做的是:

Bind<IRootScope>().To<RootScope>()
    .InNamedScope(scopeName);

然后按如下方式检索它:

IResolutionRoot.Get<IRootScope>(new NamedScopeParameter(scopeName));

这样您就不需要DefinesNamedScope()