首页 文章

WPF应用程序中的Ninject:请求类型的实例

提问于
浏览
1

我正在开发一个WPF应用程序,它具有很大的业务逻辑和数据处理能力 . 根据使用IoC的想法,我决定使用Ninject作为这部分逻辑和数据处理的依赖注入器 .

我初始化了ninject的内核,并使用 App.xaml.cs 文件中的具体类(即默认的app类)绑定了接口 . 到目前为止一切都很好 .

问题是在我的应用程序的某个地方我需要一个类的两个具体实例(我不想在构造函数中作为参数传递) . 其实我需要做的是:

var instance1 = kernel.Get<IClassName>();

问题是我无法访问 kernel (Ninject内核的具体实例) .

我知道在ASP.NET MVC中我可以做类似的事情

var instance1 = (IClassName)System.Web.Mvc.DependencyResolver.Current.GetService(typeof(IClassName));

我可以使用类似的东西吗?或者我是否被迫用服务定位器模式来解决问题(我知道存在相互矛盾的意见)?

2 回答

  • 1

    由于您希望每个类使用多个依赖项,因此您应该设计模式而不是DI容器来解决您的问题 .

    至少有几种选择 . 以下是设置场景的一些基本框架:

    public interface IPresenter
    {
        void Present();
    }
    
    public interface IConsumer
    {
        void DoSomething();
    }
    
    public class SomeConsumer : IConsumer
    {
        private readonly IPresenter presenter;
    
        public SomeConsumer(IPresenter presenter)
        {
            if (presenter == null)
                throw new ArgumentNullException("presenter");
            this.presenter = presenter;
        }
    
        public void DoSomething()
        {
            this.presenter.Present();
        }
    }
    

    您可以使用composite pattern,然后您可以在列表中订阅演示者 .

    public class Presenter1 : IPresenter
    {
        public void Present()
        {
            // Do something here
        }
    }
    
    public class Presenter2 : IPresenter
    {
        public void Present()
        {
            // Do something here
        }
    }
    
    public class Presenter3 : IPresenter
    {
        public void Present()
        {
            // Do something here
        }
    }
    
    public class CompositePresenter : IPresenter
    {
        private readonly IPresenter[] presenters;
    
        public CompositePresenter(IPresenter[] presenters)
        {
            if (presenters == null)
                throw new ArgumentNullException("presenters");
            this.presenters = presenters;
        }
    
        public void Present()
        {
            // Do nothing except delegate the call to the nested
            // instances. You may need to do some extra work to deal
            // with multiple return values, like add up the values
            // or decide which value works best for the scenario.
            foreach (var presenter in this.presenters)
            {
                presenter.Present();
            }
        }
    }
    

    然后将它连接起来:

    var presenter1 = new Presenter1();
    var presenter2 = new Presenter2();
    var presenter3 = new Presenter3();
    var compositePresenter = new CompositePresenter(new IPresenter[] {
        presenter1,
        presenter2,
        presenter3
    });
    
    var consumer = new SomeConsumer(compositePresenter);
    

    在Ninject中,上面看起来像:

    var kernel = new StandardKernel();
    kernel.Bind<Presenter1>().ToSelf();
    kernel.Bind<Presenter2>().ToSelf();
    kernel.Bind<Presenter3>().ToSelf();
    kernel.Bind<IPresenter>().To<CompositePresenter>()
        .WithConstructorArgument("presenters", 
            new IPresenter[] { 
                kernel.Get<Presenter1>(), 
                kernel.Get<Presenter2>(),
                kernel.Get<Presenter3>() 
            });
    
    // When SomeConsumer is injected into a constructor, its IPresenter 
    // dependency will be wired as shown with the new keyword example above.
    

    或者您可以使用decorator pattern

    public class Presenter1 : IPresenter
    {
        public Presenter1(IPresenter innerPresenter)
        {
            if (innerPresenter == null)
                throw new ArgumentNullException("innerPresenter");
            this.innerPresenter = innerPresenter;
        }
    
        public void Present()
        {
            // Do something here
    
            // You could make this call conditional
            this.innerPresenter.Present();
    
            // Or do something here
        }
    }
    
    public class Presenter2 : IPresenter
    {
        public Presenter2(IPresenter innerPresenter)
        {
            if (innerPresenter == null)
                throw new ArgumentNullException("innerPresenter");
            this.innerPresenter = innerPresenter;
        }
    
        public void Present()
        {
            // Do something here
    
            // You could make this call conditional
            this.innerPresenter.Present();
    
            // Or do something here
        }
    }
    
    public class Presenter3 : IPresenter
    {
        public Presenter3(IPresenter innerPresenter)
        {
            if (innerPresenter == null)
                throw new ArgumentNullException("innerPresenter");
            this.innerPresenter = innerPresenter;
        }
    
        public void Present()
        {
            // Do something here
    
            // You could make this call conditional
            this.innerPresenter.Present();
    
            // Or do something here
        }
    }
    
    public class NullPresenter : IPresenter
    {
        public void Present()
        {
            // Do nothing here - this class is a placeholder
            // in case you want to expand the design later
        }
    }
    

    然后将它连接起来:

    var nullPresenter = new NullPresenter();
    var presenter3 = new Presenter3(nullPresenter);
    var presenter2 = new Presenter2(presenter3);
    var presenter1 = new Presenter1(presenter2);
    
    var consumer = new SomeConsumer(presenter1);
    

    在Ninject中,上面看起来像:

    var kernel = new StandardKernel();
    kernel.Bind<IPresenter>().To<NullPrenter>().WhenInjectedInto<Presenter3>();
    kernel.Bind<IPresenter>().To<Presenter3>().WhenInjectedInto<Presenter2>();
    kernel.Bind<IPresenter>().To<Presenter2>().WhenInjectedInto<Presenter1>();
    kernel.Bind<IPresenter>().To<Presenter1>();
    
    // When SomeConsumer is injected into a constructor, its IPresenter 
    // dependency will be wired as shown with the new keyword example above.
    

    使用设计模式的优点是最终会得到松散耦合的代码,这些代码完全模块化,可扩展,甚至独立于DI容器 .

  • 0

    如何使用Ninject.Extensions.Factory实例化所述依赖项?你可以注入 Func<T> ,当你以后调用它时,它将返回一个新实例化的 T . 如果您只是想要实例化单个实例"on first usage",那么还有 Lazy<T> .

    然后你还可以定义接口工厂,如:

    public interface IFooFactory
    {
        IFoo Create();
    }
    

    与相应的绑定:

    Bind<IFooFactory>().ToFactory();
    Bind<IFoo>().To<Foo>(); // add Singleton, or ToMethod binding,.. or whatever you require
    

相关问题