C# 将DI与构造函数参数相结合?

C# 将DI与构造函数参数相结合?,c#,ninject,dependency-management,C#,Ninject,Dependency Management,如何将构造函数注入与“手动”构造函数参数结合起来?即 public class SomeObject { public SomeObject(IService service, float someValue) { } } 其中IService应该由我的DI容器解析/注入,并且应该指定someValue。如何将两者混合使用?如果“somevalue”始终是常量,那么您可以考虑在向容器注册类型时使用InjectionParameters,如下文所述 但如果这不是真的,那

如何将构造函数注入与“手动”构造函数参数结合起来?即

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

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

如果“somevalue”始终是常量,那么您可以考虑在向容器注册类型时使用InjectionParameters,如下文所述


但如果这不是真的,那么在解析实例时就无法指定参数值,您可能会考虑将“someValue”从构造函数中移出,并将其作为类的属性。

对此,我可能会使用一种简单的解决方案。如果您在需要时知道
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);
    }
}
你可以试试这样的图案


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

您真的不应该为此尝试使用D.I。你可以想出各种古怪的解决方案,但在今后的道路上可能没有意义


我们的方法是通过D.I.创建工厂,然后工厂的创建方法将使用传入的D.I.容器构建自己。我们不必经常使用此模式,但当我们使用此模式时,它实际上会使产品更干净(因为它使依赖关系图更小)。

在NInject中(您已将其标记为),使用

这种方法也可在autofac中使用

各种各样的


编辑:注意:虽然这可能很有趣,但请使用@Remo Gloor的解决方案(关键是建议避免这种性质的解决方案)

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

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 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);
    }
}
公共接口工厂
{
ISomeObject CreateSomeObject(浮动someValue);
}
公共类SomeObjectFactory:ISomeObjectFactory
{
私有IKernel内核;
公共对象工厂(IKernel内核)
{
this.Kernel=Kernel;
}
公共等轴测对象创建(浮点值)
{
返回this.kernel.Get(带构造函数参数(“someValue”,someValue);
}
}
预览: Ninject 2.4不再需要实现,但允许

kernel.Bind<ISomeObjectFactory>().ToFactory();  // or maybe .AsFactory();
kernel.Bind().ToFactory();//或者.AsFactory();

另一种方法-分两步初始化(与ninject无关,任何DI框架):

使用方法:

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

我不确定这是否是一个好的实践,但它可以用另一种方式解决,如果您为参数创建一个接口,然后创建一个用您需要的值(或从某处获取)实现接口的类。这样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
 ...

手动构造函数参数是指手动构造类而不是DI,还是指DI容器传入参数。如果是前者,则可以只执行构造函数重载?无论何种情况,我总是需要iSeries,因此我假设我不能只进行重载,而无需依赖项,它会神奇地使用完整的构造函数(除非我使用ServiceLocator-恶心!)。您似乎对您在
SomeObjectFactory
中选择的容器有很强的依赖性。这不是广泛推荐的做法。相反,请将
IYourService
实例注入
SomeObjectFactory
构造函数,并让容器在组合根中解决该依赖性。当然,我的代码只是一个大纲,这不是最终的实现。关键是他应该使用一个工厂。但是我根据我的想法更新了代码。+ 1明确地避免了正确的答案,编辑我的答案同意。我知道它会隐藏一点,但是在其他地方被覆盖之前考虑用FuncCor A来表达你的某个对象工厂。而不是使用内核directly@RubenBartelink:我刚刚成功实现了这个版本,因为我认为它将是Ninject 2.4的首选版本。工厂将由内核自动生成。Func变体也将得到支持,缺点是Func没有提供有关参数的信息,并且使参数匹配更加困难。因此,我不再坚持使用Func变量,只需删除工厂实现并更改绑定即可进行更新。但我也会将工厂放在引导程序中,而将接口放在消费者旁边。感谢您解释Func注入的微妙之处-我没有想到这一点。我是merely提出了一个观点,即在你手上植入工厂[2.4将自动生成],您在内核上使用了一个ctor dep,可以通过使用Func来删除。现在想想,这样做会使答案变得不那么清晰,而不会映射到
ToFactory
将要做的事情。所以,忘了我说的,谢谢您的解释!这是su_gg_est:P顺便说一句,您将方法名称输入错误为Create(不是CreateSomeObject)。我个人会优先使用Func,因为我生活在一个混乱的世界里……我喜欢这些想法——应该允许越来越少的特定于容器的东西在引导程序之外乱搞。我仍然不确定我是否喜欢所有人的默认行为
public static class TestClass
{
    public static void TestMethod(IService service)
    {
        //var someObject = new SomeObject(service, 5f);
        var someObject = new SomeObject(service).Load(5f);
    }
}
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
 ...