我决定开始使用Ninject并遇到问题。说我有以下情况。我有一个IService接口和2个实现此接口的类。而且我还有一个类,该类具有获取IService和 int 的构造函数。如何使用Ninject创建此类的实例(我不想硬连接此int,我想在每次获得实例时都将其传递)?
IService
这是一些说明情况的代码:
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(); } }
该With.ConstructorArgument为此,在1.0中存在。在2.0中,语法略有变化:- 带ninject 2.0的With.Parameters.ConstructorArgument
With.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()是您在第一个答案中放入逻辑的地方。
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
Ninject.Extensions.Factory
如前所述,如果您每次需要传递一个不同的参数,并且在依赖图中有多个级别,则可能需要执行以下操作。
最后要考虑的是,由于您没有指定a Using<Behavior>,它将默认为内核选项(TransientBehavior在示例中)中指定/默认的默认值,这可能会导致工厂i即时进行计算[例如,如果对象已被缓存]
Using<Behavior>
TransientBehavior
i
现在,要澄清正在FUD和掩盖的注释中的其他一些要点。使用DI时需要考虑的一些重要事项,无论是Ninject还是其他任何用途:
尽可能多地通过构造函数注入来完成操作,因此您无需使用特定于容器的属性和技巧。关于“ 您的IoC容器正在显示”有一篇不错的博客文章。
最小化进入容器并询问内容的代码-否则,您的代码将耦合到a)特定容器(CSL可以将其最小化)b)整个项目的布局方式。关于它的好博客文章表明CSL没有按照您的想法去做。该一般主题称为服务位置与依赖注入。更新:请参阅http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx,以获取详细而完整的原理。
尽量减少使用静态和单例
不要以为只有一个[global]容器,可以在需要的时候随便使用它,就像一个不错的全局变量一样。正确使用多个模块,并Bind.ToProvider()为您提供了管理该模块的结构。这样,每个单独的子系统都可以独立工作,并且您不会将低级组件绑定到顶级组件等。
Bind.ToProvider()
如果有人想填写指向我所指的博客的链接,我将不胜感激(尽管它们已经与SO上的其他帖子建立了链接,所以所有这些只是出于目的而引入的重复UI)避免混淆误导性答案。)
现在,如果只有乔尔(Joel)可以进来并真正让我直接了解什么是不错的语法和/或正确的方法!
更新:虽然从获得的投票数量来看,这个答案显然是有用的,但我想提出以下建议: