一尘不染

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

c#

我决定开始使用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();
    }
}

阅读 256

收藏
2020-05-19

共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还是其他任何用途:

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

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

  3. 尽量减少使用静态和单例

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

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

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

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

  • 上面的内容有点过时了,说实话反映了很多不完整的思想,自从阅读.net中的Dependency Injection之后,几乎感到很尴尬-立即运行并购买-不仅仅与DI有关,上半年是对的完整处理所有架构都围绕着一个人的想法,这个人在这里花了太多时间在依赖注入标签周围徘徊。
  • 立即在此处阅读Mark Seemann最受好评的帖子 -您将从每一本书中学习有价值的技术
2020-05-19