我决定开始使用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();
}
}
答案 0 :(得分:92)
为此目的,With.ConstructorArgument
存在于1.0中。在2.0中,语法略有改变: -
With.Parameters.ConstructorArgument with ninject 2.0
有关更多详细信息以及如何使用上下文,提供程序和参数更正确地传递此类内容的示例,请参阅Inject value into injected dependency。
编辑:由于史蒂文选择假装我的评论无关紧要,我最好通过一些例子(对于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
最后一个考虑是因为你没有指定Using<Behavior>
,它将默认为内核选项中指定/默认的默认值(样本中的TransientBehavior
)渲染事实,工厂在飞行中计算i
[例如,如果对象被缓存]
现在,澄清正在评论和掩饰的评论中的其他一些观点。关于使用DI的一些重要事项,无论是Ninject还是其他任何东西:
尽可能通过构造函数注入完成,因此您不需要使用特定于容器的属性和技巧。有一篇很好的博客文章称为Your IoC Container is Showing。
最小化代码进入容器并询问内容 - 否则您的代码将耦合到a)特定容器(CSL可以最小化)b)整个项目的布局方式。有很好的博客文章显示CSL没有做你认为它做的事情。这个一般主题称为Service Location vs Dependency Injection。更新:有关详细完整的理由,请参阅http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx。
尽量减少使用静力学和单身人士
不要假设只有一个[全局]容器,只要你需要它就像一个好的全局变量就可以。正确使用多个模块和Bind.ToProvider()
为您提供了一个管理它的结构。这样,每个独立的子系统都可以独立工作,并且您不会将低级组件与顶级组件绑定等。
如果有人想填写我所指的博客的链接,我会很感激(虽然所有这些都是关于其他帖子的,但所有这些只是重复的UI已经介绍目的是避免混淆误导性答案。)
现在,如果只有Joel可以进来并真正让我直截了当地说出了很好的语法和/或正确的方法!
更新:虽然这个答案从获得的赞成数量中明显有用,但我想提出以下建议: