15

假设我有以下要使用 Ninject 构建的类,箭头显示依赖关系。

A > B > D
A > C > D

我想配置 Ninject 使得 A 是瞬态作用域的,即每次你向 Ninject 询问 A 时,你都会得到一个新的 A。我也希望 B 和 C 是暂时的,每次你要求 A 时都会得到一个新的。但我希望D在 B 和 C 之间重复使用。所以每次我要求 A 时,我都想要 Ninject构造每个对象一个,而不是两个 D。但我不希望 Ds 在不同的 As 中重复使用。

使用 Ninject 进行设置的最佳方法是什么?

更新:
经过更多研究,Unity 似乎有一个 PerResolveLifetimeManager 可以满足我的需求。是否有 Ninject 等价物?

4

3 回答 3

15

Ninject 支持四种开箱即用的内置对象作用域:Transient、Singleton、Thread、Request。

所以没有任何类似的范围,但您可以通过使用该方法PerResolveLifetimeManager注册自定义范围来轻松实现它。InScope

事实证明,有一个现有的 Ninject 扩展:ninject.extensions.namedscope它提供了InCallScope您正在寻找的方法。

但是,如果您想自己做,您可以使用自定义InScope委托。您可以在其中使用IRequest类型的主要对象将A其用作范围对象:

var kernel = new StandardKernel();
kernel.Bind<A>().ToSelf().InTransientScope();
kernel.Bind<B>().ToSelf().InTransientScope();
kernel.Bind<C>().ToSelf().InTransientScope();
kernel.Bind<D>().ToSelf().InScope(
    c =>
        {
            //use the Request for A as the scope object                         
            var requestForA = c.Request;
            while (requestForA != null && requestForA.Service != typeof (A))
            {
                requestForA = requestForA.ParentRequest;
            }
            return requestForA;
        });

var a1 = kernel.Get<A>();    
Assert.AreSame(a1.b.d, a1.c.d);

var a2 = kernel.Get<A>();    
Assert.AreSame(a2.b.d, a2.c.d);

Assert.AreNotSame(a1.c.d, a2.c.d);

样本类在哪里:

public class A
{
    public readonly B b;
    public readonly C c;
    public A(B b, C c) { this.b = b; this.c = c; }
}

public class B
{
    public readonly D d;
    public B(D d) { this.d = d; }
}

public class C
{
    public readonly D d;  
    public C(D d) { this.d = d; }
}

public class D { }
于 2012-12-26T18:36:47.357 回答
6

我找到了解决我的具体问题的方法,即 ninject.extensions.namedscope 扩展提供的 InCallScope。这与 Unity PerResolveLifetimeManager 概念的行为相同。

于 2012-12-26T20:22:35.133 回答
1

一种替代方法是自己构建依赖项。

var kernel = new StandardKernel();
kernel.Bind<A>().ToMethod(ctx =>
{
    var d = new D();
    var c = new C(d);
    var b = new B(d);
    var a = new A(b, c);
    return a;
});

这可能不是首选方法,但它总是会构造一个A使用 , 和 的新实例的新实例BCD会重复使用DforB和的相同实例C)。您可以添加对 的调用InTransientScope(),但这不是必需的,因为它是默认范围。

于 2012-12-26T20:08:46.667 回答