如何将构造函数注入与“手动”构造函数参数组合?即
public class SomeObject
{
public SomeObject(IService service, float someValue)
{
}
}
我的DI容器应该解析/注入IService,并且应该指定someValue。我如何混合这两个?
答案 0 :(得分:30)
应尽可能避免使用此类构造。因此,问问自己:这个参数真的需要作为构造函数参数吗?或者可以将SomeObject替换为无状态的,通过将参数传递给在对象上执行的方法,每个依赖于它的每个人都可以重用它?
e.g。而不是
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<ISomeObject>(WithConstructorArgument("someValue", someValue);
}
}
预览: Ninject 2.4不再需要实现,但允许
kernel.Bind<ISomeObjectFactory>().ToFactory(); // or maybe .AsFactory();
答案 1 :(得分:2)
你真的不应该尝试使用D.I.为了这。你可以想出所有类型的古怪解决方案,但在未来可能没有意义。
我们的方法是通过D.I.创建一个工厂,然后工厂的Create方法将使用传入的D.I.自行构建。容器。我们不必经常使用这种模式,但是当我们这样做时,它实际上使产品更清洁(因为它使我们的依赖图更小)。
答案 2 :(得分:2)
另一种方法 - 分两步进行初始化(不是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);
}
}
答案 3 :(得分:1)
如果'somevalue'始终是常数,那么您可以考虑使用InjectionParameters,同时使用容器注册您的类型,如下面的帖子所述
但如果不是这样,那么在解析实例时无法分离参数值,您可能会想到从构造函数中移动'someValue'并使其成为类的属性。
答案 4 :(得分:1)
在NInject中,您使用FuncModule as described in this post以Func<parameters you wish to feed in,T>
的形式注入自动生成的工厂。
此方法也适用于autofac。
各种Factory method approaches are covered in the answers to this question。
编辑:NB虽然这可能很有趣,但请使用@Remo Gloor的解决方案(而且批判性的建议是避免这种性质的解决方案)
答案 5 :(得分:1)
我不确定这是否是一个好习惯,但是可以通过其他方式解决。如果您为参数创建接口,那么一个类将使用所需的值来实现该接口(或从某处获取) )。这样,DI也可以使用这些参数。
interface ISomeParameters
{
public float SomeValue { get; set; }
}
class SomeParameters : ISomeParameters
{
public float SomeValue{ get; set; } = 42.0;
}
services.AddSingleton(ISomeParameters, SomeParameters)
public MyService(IService service, ISomeParameters someParameters)
{
someParameters.SomeValue
...
答案 6 :(得分:0)
我可能会使用一个天真的解决方案。如果您在需要时知道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);
}
}
你可以尝试这样的模式。
更新:更新了代码以反映改进意见。