为了账号安全,请及时绑定邮箱和手机立即绑定

使用Ninject在构造函数中使用其他参数创建实例

/ 猿问

使用Ninject在构造函数中使用其他参数创建实例

C#
qq_遁去的一_1 2019-12-21 12:58:57

我决定开始使用Ninject并遇到问题。说我有以下情况。我有一个IService接口和2个实现此接口的类。而且我还有一个类,该类具有获取IService和int的构造函数。如何使用Ninject创建此类的实例(我不想硬连接此int,我想在每次获得实例时都将其传递)?


这是一些说明情况的代码:


interface IService

{

    void Func();

}


class StandardService : IService

{

    public void Func()

    {

        Console.WriteLine("Standard");

    }

}


class AlternativeService : IService

{

    public void Func()

    {

        Console.WriteLine("Alternative");

    }

}



class MyClass

{

    public MyClass(IService service, int i)

    {

        this.service = service;

    }


    public void Func()

    {

        service.Func();

    }


    IService service = null;

}

class Program

{

    static void Main(string[] args)

    {

        IKernel kernel = new StandardKernel(new InlineModule(

            x => x.Bind<IService>().To<AlternativeService>(),

            x => x.Bind<MyClass>().ToSelf()));


        IService service = kernel.Get<IService>();


        MyClass m = kernel.Get<MyClass>();

        m.Func();

    }

}


查看完整描述

1 回答

?
胡子哥哥

该With.ConstructorArgument为此,在1.0中存在。在2.0中,语法略有变化:- 带ninject 2.0的With.Parameters.ConstructorArgument


有关更多详细信息和如何使用上下文,提供程序和参数来更正确地传递类似内容的示例,请参见将值注入到注入的依赖项中。


编辑:正如史蒂文·史蒂文森(Steven)曾选择假装我的评论无关紧要,我最好通过一些示例(针对2.0)来阐明我的意思:


MyClass m = kernel.Get<MyClass>( new ConstructorArgument( "i", 2) );

在我眼中,这非常清楚,可以准确说明正在发生的事情。


如果您可以更全局地确定参数,则可以注册提供程序并按以下方式进行操作:


class MyClassProvider : SimpleProvider<MyClass>

{

    protected override MyClass CreateInstance( IContext context )

    {

        return new MyClass( context.Kernel.Get<IService>(), CalculateINow() );

    }

}

并像这样注册:


x => x.Bind<MyClass>().ToProvider( new MyClassProvider() )

注意,这CalculateINow()是您在第一个答案中放入逻辑的地方。


或者像这样使它更复杂:


class MyClassProviderCustom : SimpleProvider<MyClass>

{

    readonly Func<int> _calculateINow;

    public MyClassProviderCustom( Func<int> calculateINow )

    {

        _calculateINow = calculateINow;

    }


    protected override MyClass CreateInstance( IContext context )

    {

        return new MyClass( context.Kernel.Get<IService>(), _calculateINow() );

    }

}

您要这样注册:


x => x.Bind<MyClass>().ToProvider( new MyClassProviderCustom( (  ) => new Random( ).Next( 9 ) ) )

更新:Ninject.Extensions.Factory扩展中体现了更新的机制,该机制展现出比上面更少的样板的改进的模式,请参阅:https : //github.com/ninject/ninject.extensions.factory/wiki


如前所述,如果您每次需要传递一个不同的参数,并且在依赖图中有多个级别,则可能需要执行以下操作。


最后要考虑的是,由于您没有指定a Using<Behavior>,它将默认为内核选项(TransientBehavior在示例中)中指定/默认的默认值,这可能会导致工厂i即时进行计算[例如,如果对象已被缓存]


现在,要澄清正在FUD和掩盖的注释中的其他一些要点。使用DI时需要考虑的一些重要事项,无论是Ninject还是其他任何用途:


尽可能多地通过构造函数注入来完成操作,因此您无需使用特定于容器的属性和技巧。关于“ 您的IoC容器正在显示”有一篇不错的博客文章。


最小化进入容器并询问内容的代码-否则,您的代码将耦合到a)特定容器(CSL可以将其最小化)b)整个项目的布局方式。关于它的好博客文章表明CSL没有按照您的想法去做。该一般主题称为服务位置与依赖注入。更新:请参阅http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx,以获取详细而完整的原理。


尽量减少使用静态和单例


不要以为只有一个[global]容器,可以在需要的时候随便使用它,就像一个不错的全局变量一样。正确使用多个模块,并Bind.ToProvider()为您提供了管理该模块的结构。这样,每个单独的子系统都可以独立工作,并且您不会将低级组件绑定到顶级组件等。


如果有人想填写指向我所指的博客的链接,我将不胜感激(尽管它们已经与SO上的其他帖子建立了链接,所以所有这些只是出于目的而引入的重复UI)避免混淆误导性答案。)


现在,如果只有乔尔(Joel)可以进来并真正让我直接了解什么是不错的语法和/或正确的方法!


更新:虽然从获得的投票数量来看,这个答案显然是有用的,但我想提出以下建议:


上面的内容有点过时了,说实话反映了很多不完整的思想,自从阅读.net中的Dependency Injection之后,几乎感到很尴尬-立即运行并购买-不仅仅与DI有关,上半年是对的完整处理所有架构都围绕着一个人的想法,这个人在这里花了太多时间在依赖注入标签周围徘徊。

立即在此处阅读Mark Seemann最受好评的帖子 -您将从每一本书中学习有价值的技术


查看完整回答
反对 回复 2019-12-21

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信