将DI与构造函数参数结合起来?

如何将构造函数注入与“手动”构造函数参数组合? 即。

public class SomeObject { public SomeObject(IService service, float someValue) { } } 

我的DI容器应该解析/注入IService,并且应该指定someValue。 我该如何混合两者?

应尽可能避免使用此类构造。 因此,问问自己:这个参数真的需要作为构造函数参数吗? 或者SomeObject可以被无状态替换,通过将参数传递给您在对象上执行的方法,每个依赖于它的每个人都可以重用它。

而不是

 public class SomeObject { private float someValue public SomeObject(IService service, float someValue) { this.someValue = someValue } public float Do(float x) { return this.Service.Get(this.someValue) * x; } } 

使用

 public class SomeObject { public SomeObject(IService service) { } public float Do(float x, float someValue) { return this.Service.Get(someValue) * x; } } 

如果需要去工厂:

 public interface ISomeObjectFactory { ISomeObject CreateSomeObject(float someValue); } public class SomeObjectFactory : ISomeObjectFactory { private IKernel kernel; public SomeObjectFactory(IKernel kernel) { this.Kernel = kernel; } public ISomeObject Create(float someValue) { return this.kernel.Get(WithConstructorArgument("someValue", someValue); } } 

预览:Ninject 2.4不再需要实现,但允许

 kernel.Bind().ToFactory(); // or maybe .AsFactory(); 

如果’somevalue’始终是常数,那么您可以考虑使用InjectionParameters,同时使用容器注册您的类型,如下面的post所述

看这里

但如果不是这样,那么在解析实例时无法分离参数值,您可能会想到从构造函数中移动’someValue’并使其成为类的属性。

你真的不应该尝试使用DI。 你可以提出各种古怪的解决方案,但在未来可能没有意义。

我们的方法是通过DI创建工厂,然后工厂的Create方法将使用传入的DI容器自行构建。 我们不必经常使用这种模式,但是当我们这样做时,它实际上使产品更清洁(因为它使我们的依赖图更小)。

在NInject中,您已使用此标记对其进行了标记,您将使用FuncModule以FuncModule的forms注入一个自动生成的工厂,这些Func , 如本文所述 。

这种方法也可以在autofac中使用。

本问题的答案涵盖了各种工厂方法方法 。

编辑:NB虽然这可能是有趣的,请使用@Remo Gloor的解决方案(并批判性的建议,避免这种性质的解决方案)

另一种方法 – 初始化分两步(不是ninject相关,任何DI框架):

 public class SomeObject { private readonly IService _service; public SomeObject(IService service) { // constructor only captures dependencies _service = service; } public SomeObject Load(float someValue) { // real initialization goes here // .... // you can make this method return no value // but this makes it more convienient to use return this; } } 

和用法:

 public static class TestClass { public static void TestMethod(IService service) { //var someObject = new SomeObject(service, 5f); var someObject = new SomeObject(service).Load(5f); } } 

我可能会使用一个天真的解决方案。 如果你在需要时知道someValue的值,我会从构造函数中删除它并向你的对象添加一个属性,这样你就可以设置someValue 。 这样,您可以从容器中获取对象,然后在拥有对象时设置值。

我的另一个建议是,您不是直接访问它而是创建一个可用于创建此类对象的工厂。 然后在容器中注册工厂并使用工厂创建实例。 像这样的东西:

 public class SomeObjectFactory : ISomeObjectFactory { private IYourService _service; public SomeObjectFactory(IYourService service) { _service = service; } public ISomeObject Create(float someValue) { return new SomeObject(_service, someValue); } } 

你可以尝试这样的模式。

更新:更新代码以反映改进意见。