结合DI和构造函数参数?

Geo*_*e R 35 c# ninject dependency-management

如何将构造函数注入与"手动"构造函数参数组合?即.

public class SomeObject
{
    public SomeObject(IService service, float someValue)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Rem*_*oor 34

应尽可能避免使用此类构造.因此,问问自己:这个参数真的需要作为构造函数参数吗?或者可以将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;
    }
}
Run Code Online (Sandbox Code Playgroud)

使用

public class SomeObject
{
    public SomeObject(IService service)
    {
    }

    public float Do(float x, float someValue)
    {
        return this.Service.Get(someValue) * x;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果需要去工厂:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

kernel.Bind<ISomeObjectFactory>().ToFactory();  // or maybe .AsFactory();
Run Code Online (Sandbox Code Playgroud)


Are*_*rek 6

另一种方法 - 分两步初始化(与 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

和用法:

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

  • 当忘记调用Load方法时,这是不安全的。 (2认同)

Bee*_*eep 5

您真的不应该尝试为此使用 DI。你可以想出所有类型的古怪解决方案,但它们在未来可能没有意义。

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