将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); } }
你可以尝试这样的模式。
更新:更新代码以反映改进意见。