Ninject 与 WhenInjectedInto 扩展方法绑定

发布于 2024-12-05 01:34:35 字数 2368 浏览 0 评论 0 原文

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

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

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

基本上程序流程是ClassA创建ClassB并执行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班您好,

谢谢

I feel I am missing something obvious. I've read several related questions on here and I've read the updated contextual bindings page on Ninject's wiki but alas it still doesn't work.

I am trying to retrofit a legacy application that used a factory pattern to use Ninject.

I have 1 interface (IInterface) implemented by 2 classes (ClassB and ClassC). IInterface has a load method. In ClassB's load method it instantiates ClassC and then executes it's load method.

Basically the program flow is ClassA creates ClassB and executes the load method. In the load method ClassB creates ClassC that does some work.

My bindings are setup as so...

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

When this runs it fails in ClassB's load method with this error...

Error activating IInterface No matching bindings are available, and the type is not self-bindable.

If I try the following...

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

It does an endless loop and never creates ClassC.

EDIT
I have simplified this into a unit test that passes but doesn't give me the results I want...

[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();
    }

The output is:
Hello from Class C
Hello from Class A

But I want:
Hello from Class C
Hello from Class B
Hello from Class A

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

七度光 2024-12-12 01:34:35

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

不要将内核作为参数传递 - 这样做不是依赖注入,而是服务位置(关于差异的好文章:服务定位器是一种反模式)。

将 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 进行相同的更改(传递您想要解析的类型/接口,而不是内核)。

You are not injecting into ClassC. You are passing in the kernel and resolving IDoSomething directly from it. There is a big difference.

Do not pass the kernel as a parameter--doing so is not Dependency Injection, it is Service Location (good article on the difference: Service Locator is an Anti-Pattern).

Change ClassC to be:

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();          
    }     
} 

You should also make the same changes to ClassA and ClassB (pass the type/interface you want resolved, not the kernel).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文