将 DI 与构造函数参数结合起来?
如何将构造函数注入与“手动”构造函数参数结合起来? IE。
public class SomeObject
{
public SomeObject(IService service, float someValue)
{
}
}
其中 IService 应由我的 DI 容器解析/注入,并且应指定 someValue。我如何混合两者?
How do I combine constructor injection with "manual" constructor parameters? ie.
public class SomeObject
{
public SomeObject(IService service, float someValue)
{
}
}
Where IService should be resolved/injected by my DI container, and someValue should be specified. How do I mix the two?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
应尽可能避免此类构造。因此,问问自己:这个参数真的需要作为构造函数参数吗?或者,SomeObject 是否可以替换为无状态对象,通过将参数传递给您在该对象上执行的方法,所有依赖它的人都可以重用该对象?
例如,而不是
使用
如果需要去工厂:
预览:
Ninject 2.4 不再需要实现,但允许
Such constructs should be avoided whenever possible. Therefore, ask yourself: is this parameter really required as constructor argument? Or can SomeObject be replaced by a stateless one which is reused by everyone that depends on it by passing the parameter to the method you execute on the object?
e.g. Instead of
use
If it is required go for a factory:
Preview:
Ninject 2.4 won't require the implementation anymore but allow
你真的不应该尝试为此使用 DI。您可以想出各种古怪的解决方案,但它们可能在未来没有意义。
我们的方法是通过 DI 创建一个工厂,然后工厂的 Create 方法将使用传入的 DI 容器构建自身。我们不必经常使用这种模式,但当我们这样做时,它实际上会使产品变得更加干净(因为它使我们的依赖关系图更小)。
You really shouldn't try to use D.I. for this. You could come up with all types of wacky solutions, but they may not make sense down the road.
Our approach is to create a factory via D.I., and the factory's Create method would then build itself out using the passed in D.I. container. We don't have to use this pattern often, but when we do it actually makes the product much cleaner (since it makes our dependency graphs smaller).
另一种方法 - 分两步初始化(与 ninject 无关,任何 DI 框架):
和用法:
Another approach - initialization in two steps (not ninject related, any DI framework):
and usage:
我不确定这是一个好的做法,但可以用不同的方式解决,如果您为参数创建一个接口,然后使用您需要的值(或从某处获取)实现该接口的类。这样 DI 也可以处理这些参数。
I am not sure this is a good practice, but it could be solved in a different way, If you create an interface for the parameters, then a class that implements the interface with the values that you need (or fetch from somewhere). That way DI works with those parameters as well.
我可能会使用一个简单的解决方案来解决这个问题。如果您在需要时知道
someValue
的值,我会将其从构造函数中删除,并向您的对象添加一个属性,以便您可以设置someValue
。这样您就可以从容器中获取对象,然后在获得该对象时设置该值。我的另一个建议是,您不要直接访问它,而是创建一个可用于创建此类对象的工厂。然后,您在容器中注册工厂并使用该工厂创建实例。像这样的事情:
你可以尝试这样的模式。
更新:更新了代码以反映改进意见。
I would probably use a naive solution to this. If you know the value of
someValue
when you need it I would remove it from the constructor and add a property to your object so you can setsomeValue
. This way you can get your object from your container and then set the value when you have the object.My other suggestion is that you instead of accessing it directly you create a factory that you can use to create such object. Then you register the factory in your container and use the factory to create your instance. Something like this:
you could try a pattern like that.
UPDATE: Updated the code to reflect improvement comments.
如果“somevalue”始终是常量,那么您可以在向容器注册类型时考虑使用 InjectionParameters,如下面的文章中所述
请参阅此处
,但如果情况并非如此,则在解析实例时无法指定参数值,您可能会考虑移动来自构造函数的“someValue”,并将其作为类的属性。
If 'somevalue' is always constant then you can think of using InjectionParameters while you are register your type with the container as it explained in the below post
See Here
but if that is not true, than there is no way to sepcify a parameter value while resolving a instance , you may think of moving the 'someValue' from the constructor and make it a property of the class.
在您已标记的 NInject 中,您可以使用 FuncModule 如本文所述。
autofac 中也提供了这种方法。
各种工厂方法方法都在这个问题的答案。
编辑:注意虽然这可能很有趣,但请使用@Remo Gloor的解决方案(并且重要的是避免使用这种性质的解决方案的建议)
In NInject, which you have tagged this with, you inject an automatically-generated Factory in the form of a
Func<parameters you wish to feed in,T>
, using the FuncModule as described in this post.This approach is also available in autofac for one.
The various Factory method approaches are covered in the answers to this question.
EDIT: NB While this may be entertaining, please use @Remo Gloor's solution (and critically the advice re avoiding a solution of this nature)
这不正是
DI\Container::make()
是为了?Isn't this exactly what
DI\Container::make()
is for?我使用的方法是将这些参数定义为抽象属性。然后创建一个新的子类。它类似于 AndersK 方法。这不是一个解决方案,但它适合我的需求:
而不是
你可以做
The approach I used was to define those parameters as abstract properties. And then create a new child class. It is similar to AndersK approach. It is not a go to solution but it suited my needs:
Instead of
You can do