Ninject 解析接口时未解析为已配置的单例

Ninject not resolving to a configured singleton when resolving an interface

我有一个使用 Ninject 作为 DI 的应用程序。我正在添加一些新的 classes,但它们没有按照我认为应该的方式得到解决。

我有一个 class Foo 实现了接口 ISomething。如果我这样配置绑定:

kernel.Bind<Foo>().ToSelf().InSingletonScope();
kernel.Bind<ISomething>().To<Foo>();

然后做:

var foo1 = kernel.Get<Foo>();
var foo2 = kernel.Get<ISomething>();

这两个变量有 Foo class 的不同实例。

如果我将绑定更改为:

kernel.Bind<Foo>().ToSelf().InSingletonScope();
kernel.Bind<ISomething>().ToMethod(ctx => ctx.Kernel.Get<Foo>());

然后做:

var foo1 = kernel.Get<Foo>();
var foo2 = kernel.Get<ISomething>();

这两个变量具有相同的实例。

我的理解是,在第一种情况下,它应该将 ISomething 解析为 Foo,后者又将解析为自身的单例。是我的理解不正确,还是其他地方不对?必须手动解决它似乎有点多余。

当您在注册中省略生活方式时,按照惯例,Ninject 使用短暂的生活方式。这意味着:

kernel.Bind<ISomething>().To<Foo>();

相当于:

kernel.Bind<ISomething>().To<Foo>().InTransientScope();

加上生活方式,更容易发现问题:

kernel.Bind<Foo>().ToSelf().InSingletonScope();
kernel.Bind<ISomething>().To<Foo>().InTransientScope();

或者更清楚:

kernel.Bind<Foo>()       .To<Foo>().InSingletonScope();
kernel.Bind<ISomething>().To<Foo>().InTransientScope();

在这里您可以看到您正在注册 Foo 作为单例和瞬态。这种错误配置是一个常见的陷阱,称为 Ambiguous Lifestyles:

When multiple registrations with a different lifestyle map to the same component, the component is said to have ambiguous lifestyles. Having one single component with multiple lifestyles will cause instances of that component to be cached in different ways and this can lead to behavior that you might not expect.

一些 DI 容器确实包含可用于检测此类错误配置的验证机制,但我熟悉的所有 DI 容器都允许您以这种方式意外地错误配置容器。