C# 在构造函数中使用带有附加参数的 Ninject 创建实例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2227548/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Creating an instance using Ninject with additional parameters in the constructor
提问by StuffHappens
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)?
我决定开始使用 Ninject 并面临一个问题。假设我有以下场景。我有一个IService
接口和 2 个实现这个接口的类。而且我还有一个类,它有一个构造函数获取 IService 和一个int。如何使用 Ninject 创建此类的实例(我不想硬连线这个 int,我想在每次获得实例时传递它)?
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();
}
}
采纳答案by Ruben Bartelink
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
该With.ConstructorArgument
为此,在1.0中存在。在 2.0 中,语法略有变化:-
With.Parameters.ConstructorArgument with ninject 2.0
See Inject value into injected dependencyfor 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):
编辑:由于史蒂文选择假装我的评论无关紧要,我最好通过一些示例(对于 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.
请注意,这CalculateINow()
一点是您在第一个答案中放入逻辑的地方。
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
更新:在Ninject.Extensions.Factory
扩展中体现了比上述模式更少的改进模式的更新机制,请参阅: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]
最后一个考虑是,因为您没有指定 a Using<Behavior>
,它将默认为内核选项中指定/默认的默认值(TransientBehavior
在示例中),这可能会导致工厂i
实时计算的事实[例如,如果对象被缓存]
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:
现在,澄清评论中的其他一些被 FUD 和掩盖的观点。关于使用 DI 需要考虑的一些重要事项,无论是 Ninject 还是其他任何东西:
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.
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.aspxfor a detailed and complete rationale.
Minimise use of statics and singletons
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.
尽可能多地通过构造函数注入完成,这样您就不需要使用容器特定的属性和技巧。有一篇很好的博客文章叫做Your IoC Container is Showing。
尽量减少进入容器并请求内容的代码 - 否则您的代码会与 a) 特定容器(CSL 可以最小化)b) 整个项目的布局方式耦合。有很好的博客文章表明 CSL 并没有按照您的想法行事。这个一般主题被称为服务位置与依赖注入。更新:请参阅http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx了解详细和完整的基本原理。
尽量减少静态和单例的使用
不要假设只有一个 [global] 容器,并且只要您需要它就可以像一个不错的全局变量一样要求它。正确使用多个模块并
Bind.ToProvider()
为您提供一个结构来管理它。这样每个单独的子系统都可以独立工作,并且您不会将低级组件绑定到顶级组件等。
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.)
如果有人想填写我所指的博客的链接,我将不胜感激(尽管它们都已经从 SO 上的其他帖子链接了,所以所有这些都只是重复的 UI 引入的目的避免误导性答案的混淆。)
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!
现在,如果 Joel 能进来并真正让我了解什么是好的语法和/或正确的方法来做到这一点就好了!
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
- 以上感觉有点过时,老实说反映了很多不完整的想法,自从阅读.net中的依赖注入以来几乎感觉很尴尬- 立即运行并购买 - 这不仅仅是关于DI,前半部分是一个完整的处理围绕它的所有架构问题都来自一个在依赖注入标签上花费太多时间的人。
- 立即在 SO 上阅读Mark Seemann 评分最高的帖子- 您将从每个人那里学到宝贵的技术