Ninjectシングルトンスコープクラスが複数回構築されているという問題があります。私はコードを、奇妙な振る舞いを示す例に縮小しました。ハンドラは、Handlerコンストラクタによって実行されるやや複雑な初期化を持つModuleで構成されるシングルトンです。これが、ToMethod()を使用してモジュールをバインドする理由です。パートもシングルトンであり、パートが作成された場合はハンドラが作成されることが非常に重要です。そのため、パートOnActivationコールバックでハンドラをリクエストしています。複数のインスタンスを作成するNinjectのInSingletonScope()
IKernel kernel = new StandardKernel();
kernel.Bind<Handler>().ToSelf().InSingletonScope();
kernel.Bind<Module>().ToMethod(x => x.Kernel.Get<Handler>().Module);
kernel.Bind<Part>().ToSelf().InSingletonScope().OnActivation(_ => kernel.Get<Handler>());
いくつかのデバッグ出力を含む完全なコード:
[Test]
public void NinjectShouldCreateOnlyOneHandler()
{
IKernel kernel = new StandardKernel();
kernel.Bind<Handler>().ToSelf().InSingletonScope();
kernel.Bind<Module>().ToMethod(x =>
{
Debug.WriteLine("Module ToMethod enter");
Module module = x.Kernel.Get<Handler>().Module;
Debug.WriteLine("Module ToMethod exit");
return module;
});
kernel.Bind<Part>().ToSelf().InSingletonScope().OnActivation(_ =>
{
Debug.WriteLine("Part OnActivation enter");
kernel.Get<Handler>();
Debug.WriteLine("Part OnActivation exit");
});
Debug.WriteLine("Get<Module>()");
kernel.Get<Module>();
Debug.WriteLine($"InstanceCount = {Handler.InstanceCount}");
Assert.AreEqual(1, Handler.InstanceCount);
}
public class Handler
{
public static int InstanceCount { get; private set; } = 0;
public Handler(Part part)
{
Debug.WriteLine($"Handler ctor, InstanceCount = {++InstanceCount}");
Module = new Module(part);
}
public Module Module { get; }
}
public class Module
{
public Module(Part part)
{
Debug.WriteLine("Module ctor");
}
}
public class Part
{
public Part()
{
Debug.WriteLine("Part ctor");
}
}
デバッグ出力:
Get<Module>()
Module ToMethod enter
Part ctor
Part OnActivation enter
Handler ctor, InstanceCount = 1
Module ctor
Part OnActivation exit
Handler ctor, InstanceCount = 2
Module ctor
Module ToMethod exit
InstanceCount = 2
私はこの問題は、それが作成されている間、私たちはハンドラのインスタンスを要求していることだと思い、その時点で構築できるため、そのインスタンスが次の要求に使用されないのはなぜですか?
Ninjectは、シングルトンスコープクラスの2つのインスタンスを作成する代わりに、むしろ例外をスローすると思います。これはバグですか、私が逃したことがありますか?私たちはNinject v3.2.2を使用しています。
OnActivationコールバックの中にハンドラ*を作成することはできますが、別のハンドラを作成する代わりに元の要求に格納されて返されない理由を理解できません。また、Ninjectがそれを行うことができない場合、シングルトンとしてマークされたクラスの複数のインスタンスを作成する代わりに、例外がスローされることが予想されます。私はこれをNinjectの開発者に報告する必要があると思います。 – Anlo