【问题标题】:Ninject binding with WhenInjectedInto extension methodNinject 与WhenInjectedInto 扩展方法的绑定
【发布时间】:2011-09-17 22:25:43
【问题描述】:

我觉得我遗漏了一些明显的东西。我在这里阅读了几个相关的问题,并且阅读了 Ninject wiki 上更新的上下文绑定页面,但可惜它仍然不起作用。

我正在尝试改造一个使用工厂模式的遗留应用程序以使用 Ninject。

我有 1 个接口 (IInterface) 由 2 个类(ClassB 和 ClassC)实现。 IInterface 有一个加载方法。在 ClassB 的 load 方法中,它实例化 ClassC,然后执行它的 load 方法。

基本上程序流程是ClassA创建ClassB并执行load方法。在 load 方法中 ClassB 创建了 ClassC 来做一些工作。

我的绑定是这样设置的...

Bind<IInterface>().To<ClassC>().WhenInjectedInto<ClassB>();
Bind<IInterface>().To<ClassB>().WhenInjectedInto<ClassA>();

当它运行时,它在 ClassB 的加载方法中失败并出现此错误...

激活 IInterface 时出错 没有匹配的绑定可用,并且类型不是自绑定的。

如果我尝试以下...

Bind<IInterface>().To<ClassC>().WhenInjectedInto<ClassB>();
Bind<IInterface>().To<ClassB>();

它执行一个无限循环并且从不创建 ClassC。

编辑 我已将其简化为通过但没有给我想要的结果的单元测试...

[TestClass]
public class NinjectTestFixture
{
    private interface IDoSomething
    {
        void SaySomething();
    }

    private class ClassA : IDoSomething
    {
        public void SaySomething()
        {
            Console.WriteLine("Hello from Class A");
        }
    }

    private class ClassB : IDoSomething
    {
        private IKernel _Kernel;

        public ClassB(IKernel kernel)
        {
            _Kernel = kernel;
        }

        public void SaySomething()
        {
            Console.WriteLine("Hello from Class B");

            var x = _Kernel.Get<IDoSomething>();

            x.SaySomething();
        }
    }

    private class ClassC
    {
        private IKernel _Kernel;

        public ClassC(IKernel kernel)
        {
            _Kernel = kernel;
        }

        public void SaySomething()
         {
             Console.WriteLine("Hello from Class C");

             var x = _Kernel.Get<IDoSomething>();

             x.SaySomething();
         }
    }

    [TestMethod]
    public void TestMethod1()
    {
        var kernel = new StandardKernel();

        kernel.Bind<IDoSomething>().To<ClassA>();
        kernel.Bind<IDoSomething>().To<ClassB>().WhenInjectedInto<ClassC>();
        kernel.Bind<ClassC>().ToSelf();

        var x = kernel.Get<ClassC>();

        x.SaySomething();
    }

输出是: C班的你好 A班同学你好

但我想要: C班的你好 B班的你好 A班同学你好

谢谢

【问题讨论】:

    标签: c# dependency-injection ninject ninject-2


    【解决方案1】:

    没有注入 ClassC。您正在传入内核并直接从中解析 IDoSomething。有很大的不同。

    不要将内核作为参数传递——这样做不是依赖注入,而是服务位置(关于区别的好文章:Service Locator is an Anti-Pattern)。

    将 ClassC 更改为:

    private class ClassC     
    {         
        private IDoSomething _doSomething;          
        public ClassC(IDoSomething doSomething)
        {             
            _doSomething = doSomething;         
        }          
    
        public void SaySomething()          
        {              
            Console.WriteLine("Hello from Class C");               
            //var x = _Kernel.Get<IDoSomething>();               
            _doSomething.SaySomething();          
        }     
    } 
    

    您还应该对 ClassA 和 ClassB 进行相同的更改(传递您想要解析的类型/接口,而不是内核)。

    【讨论】:

    • 我明白你在说什么,但是在 SaySomething 方法中我需要实例化一个对象来做一些工作。在同一个类中,还有其他方法可以实例化方法来完成更多工作。如果我按照您的建议进行操作,我的构造函数中将有大约 20 个参数。该代码最初是在 6 年前编写的,因此我正在尝试使用 DI 逐步对其进行改造。我已经绞尽脑汁思考如何做到这一点,而传递内核是最简单、最有意义的解决方案。我查看了服务位置,考虑到当前的代码库,这没有意义。
    • 你的回答是正确的。当我做出您提议的更改时,我得到了预期的结果。
    • 我明白你的意思——我也重构了系统,我不得不使用一些奇怪/丑陋的临时步骤来引入 DI。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多