创建使用Ninject在构造函数中附加参数实例 [英] Creating an instance using Ninject with additional parameters in the constructor

查看:398
本文介绍了创建使用Ninject在构造函数中附加参数实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我决定开始使用Ninject和面临的问题。说我有以下情形。
我有一个 IService 接口和2类实现此接口。同时,我有一个类,它有一个构造函数得到IService和 INT 。我怎样才能创建这个类Ninject的一个实例(我不想硬连线这个中断,我想我都能实例时通过它)?

下面是一些code说明情况:

 接口IService
{
    无效Func键();
}类StandardService:IService
{
    公共无效Func键()
    {
        Console.WriteLine(标准);
    }
}类AlternativeService:IService
{
    公共无效Func键()
    {
        Console.WriteLine(替代);
    }
}
MyClass类
{
    公共MyClass的(IService服务,int i)以
    {
        this.service =服务;
    }    公共无效Func键()
    {
        service.Func();
    }    IService服务= NULL;
}
类节目
{
    静态无效的主要(字串[] args)
    {
        的iKernel内核=新StandardKernel(新InlineModule(
            X => x.Bind&所述; IService方式>()到< AlternativeService>(),
            X => x.Bind&所述; MyClass的>()ToSelf()))。        IService服务= kernel.Get< IService>();        MyClass的M = kernel.Get< MyClass的>();
        m.Func();
    }
}


解决方案

With.ConstructorArgument 1.0存在这一目的。在2.0中,语法已略有改变: -
<一href=\"http://stackoverflow.com/questions/1374098/with-parameters-constructorargument-with-ninject-2-0\">With.Parameters.ConstructorArgument与ninject 2.0

有关详细信息,以及如何使用示例请参见注入到价值注入的依赖的背景下,供应商和参数传递这样的东西围绕更加准确。

编辑:史蒂芬先后当选为pretend我的意见是无关紧要的,我最清楚什么,我有一些例子说(2.0):

  MyClass的M = kernel.Get&LT; MyClass的&GT;(新ConstructorArgument(I,2));

这在我眼里是很清楚的,并指出究竟发生了什么。

如果你在一个位置,你可以确定一个更具全球性的方式,你可以注册一个供应商,做这样的参数:

 类MyClassProvider:SimpleProvider&LT; MyClass的&GT;
{
    保护覆盖MyClass的的CreateInstance(IContext上下文)
    {
        返回新MyClass的(context.Kernel.Get&所述; IService&GT;(),CalculateINow());
    }
}

和注册它是这样的:

  X =&GT; x.Bind&所述; MyClass的方式&gt;()ToProvider(新MyClassProvider())

NB的 CalculateINow()位就是你把你的逻辑在第一个答案。

,或使其更复杂的是这样的:

 类MyClassProviderCustom:SimpleProvider&LT; MyClass的&GT;
{
    只读Func键&LT; INT&GT; _calculateINow;
    公共MyClassProviderCustom(Func键&LT; INT&GT; calculateINow)
    {
        _calculateINow = calculateINow;
    }    保护覆盖MyClass的的CreateInstance(IContext上下文)
    {
        返回新MyClass的(context.Kernel.Get&所述; IService&GT;(),_calculateINow());
    }
}

您想注册像这样:

  X =&GT; x.Bind&LT; MyClass的方式&gt;()ToProvider(新MyClassProviderCustom(()=&GT;新的随机()。接下来(9)))

更新:表现出比上述体现在 Ninject.Extensions.Factory 扩展更少的样板大大改善了较新的模式机制,请参阅:
<一href=\"https://github.com/ninject/ninject.extensions.factory/wiki\">https://github.com/ninject/ninject.extensions.factory/wiki

如前所述,如果你需要每次都通过不同的参数,你有多个级别在依赖关系图中,你可能需要做这样的事情

最后需要考虑的是,因为你没有指定一个使用&LT;行为&GT; ,它会在为内核指定的选项/默认为默认为默认( TransientBehavior 样品中),这可能使事实工厂计算 I 飞没有实际意义[例如,如果该对象被缓存]

现在,要以正在FUDed并轻轻带过的评论澄清一些其他问题。一些重要的事情要考虑有关使用DI,无论是Ninject或任何其他是:


  1. 有尽可能多地通过构造器注入这样做你不需要使用容器特定的属性和技巧。有一个良好的博客文章,呼吁你的IoC容器是显示


  2. 最小化code将容器并要求东西 - 否则你的code耦合到)特定的容器(其中,CSL可以最小化),B)的方式在整个项目正在布局。有上显示,CSL心不是做什么,你认为它确实很好的博客文章。这是一般的主题被称为服务定位VS依赖注入。更新:请参阅<一个href=\"http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx\">http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx进行了详细和完整的理由。


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


  4. 不要以为只有一种(全球)的容器,它没关系只要你需要它像一个很好的全局变量,只是需要它。正确使用多个模块和 Bind.ToProvider()让你来管理这个结构。这样,每个单独的子系统可独立工作,你不会有低级别的组件被捆绑到顶层组件等。


如果有人想填补的链接,我指的是博客,我AP preciate说(他们都已经从其他岗位上的链接,虽然SO,所以这一切仅仅是重复UI've介绍了避免误导答案的混乱的目的。)

现在,只要乔尔能进来,真正让我直上有什么好的语法和/或做这正道!

更新:虽然这个答案是它囊括upvotes数量显然很有用,我想提出以下建议:


  • 上面的感觉,因为它是一个有点过时,要诚实反映了很多不完整的思考,几乎感觉尴尬,因为读的在.net中依赖注入 - 运行,现在买它 - 它不只是DI,上半年是谁已经在这里度过了太多的时间游逛的都是从一个人周围的建筑关注一个完整的治疗依赖注入的标签。

  • 的。所以现在在这里阅读马克·塞曼的最高额定帖子 - 你会从每个人
  • 学到有价值的技巧

I decided to start using Ninject and face an issue. Say I have the following scenario. I have an IService interface and 2 classes implementing this interface. And also I have a class, which has a constructor getting IService and an int. How can I create an instance of this class with Ninject (I dont want to hardwire this int, I want to pass it every time I get an instance)?

Here's some code illustrating the situation:

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

解决方案

The With.ConstructorArgument existed in 1.0 for this purpose. In 2.0, the syntax has changed slightly:- With.Parameters.ConstructorArgument with ninject 2.0

See Inject value into injected dependency for more details and examples of how to use the context, providers and arguments to pass stuff like this around more correctly.

EDIT: As Steven has elected to pretend my comment is irrelevant, I'd best make clear what I'm saying with some examples (for 2.0):

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

which to my eyes is very clear and states exactly what's happening.

If you're in a position where you can determine the parameter in a more global way you can register a provider and do it like this:

class MyClassProvider : SimpleProvider<MyClass>
{
    protected override MyClass CreateInstance( IContext context )
    {
        return new MyClass( context.Kernel.Get<IService>(), CalculateINow() );
    }
}

And register it like this:

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

NB the CalculateINow() bit is where you'd put in your logic as in the first answer.

Or make it more complex like this:

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

Which you'd register like so:

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

UPDATE: Newer mechanisms which exhibit much improved patterns with less boilerplate than the above are embodied in the Ninject.Extensions.Factory extension, see: https://github.com/ninject/ninject.extensions.factory/wiki

As stated earlier, if you need to pass a different parameter each time and you have multiple levels in the dependency graph, you might need to do something like this.

A final consideration is that because you haven't specified a Using<Behavior>, it's going to default to the default as specified/defaulted in the options for the kernel (TransientBehavior in the sample) which might render fact that the factory calculates i on the fly moot [e.g., if it the object was being cached]

Now, to clarify some other points in the comments that are being FUDed and glossed over. Some important things to consider about using DI, be it Ninject or whatever else is to:

  1. Have as much as possible done by constructor injection so you dont need to use container specific attributes and tricks. There's a good blog post on that called Your IoC Container is Showing.

  2. Minimise code going to the container and asking for stuff - otherwise your code is coupled to a) the specific container (which the CSL can minimise) b) the way in which your entire project is laid out. There are good blog posts on that showing that CSL isnt doing what you think it does. This general topic is referred to as Service Location vs Dependency Injection. UPDATE: See http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx for a detailed and complete rationale.

  3. Minimise use of statics and singletons

  4. Don't assume there is only one [global] container and that it's OK to just demand it whenever you need it like a nice global variable. The correct use of multiple modules and Bind.ToProvider() gives you a structure to manage this. That way each separate subsystem can work on its own and you wont have low-level components being tied to top-level components, etc.

If someone wants to fill in the links to the blogs I'm referring to, I'd appreciate that (they're all already linked from other posts on SO though, so all of this is just duplication UI've introduced with the aim of avoiding the confusion of a misleading answer.)

Now, if only Joel could come in and really set me straight on what's nice syntax and/or the right way to do this!

UPDATE: While this answer is clearly useful from the number of upvotes it's garnered, I'd like to make the following recommendations:

  • The above feels as it's a bit dated and to be honest reflects a lot of incomplete thinking which almost feels embarassing since reading Dependency Injection in .net - Run and buy it now - it's not just about DI, the first half is a complete treatment of all the architecture concerns surrounding it from a man who has spent way too much time here hanging around the dependency injection tag.
  • Go read Mark Seemann's top rated posts here on SO right now - you'll learn valuable techniques from every one

这篇关于创建使用Ninject在构造函数中附加参数实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆