0

コード ライブラリ内のサービス プロバイダーのスコープと有効期間の規則を知っているコード ライブラリでサービスを提供するケースがいくつかあります。その情報をライブラリ自体で構成したいと考えていますが、その知識をコンポジション ルートにバブリングする必要はありません。

現在のバージョンの Ninject でこれを実装できるかどうかはわかりません。

using System;
using System.Diagnostics.CodeAnalysis;
using Ninject;
using Ninject.Extensions.Conventions;
using NUnit.Framework;
using Ninject.Modules;

[TestFixture]
public class Spike
{
    private IKernel kernel;

    [SetUp]
    public void SetUp()
    {
        this.kernel = new StandardKernel();

        this.kernel.Load(new Registry());

        this.kernel.Bind(x => x
            .FromThisAssembly()
            .SelectAllClasses()
            .BindAllInterfaces()
            );
    }

    [TearDown]
    public void TearDown()
    {
        Thing1.ResetCounts();
    }

    [Test]
    public void GetThing1AndThing2()
    {
        // arrange
        var thing1 = this.kernel.Get<Thing1>();
        var thing2 = this.kernel.Get<Thing1>();

        // act
        thing1.DoTheWork();
        thing2.DoTheWork();

        // assert
        Assert.AreEqual(1, Thing1.ConstructorCount, "wrong number of constructor invocations");
        Assert.AreEqual(2, Thing1.DoTheWorkCount, "wrong number of method invocations");
    }

    [Test]
    public void GetIThing1AndIThing2()
    {
        // arrange
        var thing1 = this.kernel.Get<IThing1>();
        var thing2 = this.kernel.Get<IThing1>();

        // act
        thing1.DoTheWork();
        thing2.DoTheWork();

        // assert
        Assert.AreEqual(1, Thing1.ConstructorCount, "wrong number of constructor invocations");
        Assert.AreEqual(2, Thing1.DoTheWorkCount, "wrong number of method invocations");
    }

    public class Registry : NinjectModule
    {
        public override void Load()
        {
            Bind<Thing1>().ToSelf().InSingletonScope();
        }
    }

    public interface IThing1
    {
        void DoTheWork();
    }

    public class Thing1 : IThing1
    {
        public static int ConstructorCount { get; set; }
        public static int DoTheWorkCount { get; set; }

        public Thing1()
        {
            Console.WriteLine("Thing1.ctor underway");
            ++Thing1.ConstructorCount;
        }

        public void DoTheWork()
        {
            Console.WriteLine("Thing1.DoTheWork underway");
            ++Thing1.DoTheWorkCount;
        }

        public static void ResetCounts()
        {
            Thing1.ConstructorCount = 0;
            Thing1.DoTheWorkCount = 0;
        }
    }
}

このテスト ケースでは、ilbrary は、、、およびクラスRegistryで表されます。ライブラリのユーザーはテスト フィクスチャであり、メソッドはライブラリ ユーザーに記述してもらいたいコードを示します (オブジェクトを新規作成する代わりに、dll を含むパスを渡します)。Thing1IThing1Spike.SetUp()Registry

Thing1記述されたコードを使用すると、サービスを複数回フェッチするとSpike.GetThing1AndThing2()、目的のシングルトン動作が示されます。Thing1のように、公開されたインターフェイスを介してサービスを複数回フェッチしSpike.GetIThing1AndIThing2()ても、シングルトンの動作は見られず、2 つの個別Thing1のオブジェクトが構築されます。

それで、私が求めていることを行うことは可能ですか: コンポジションルートが形成されたときにスキャンを実行しながら、DLL 自体でシングルトンの動作を指定することはできますか?

4

1 に答える 1

1

規約を導入する必要があります。たとえば、スコープを指定する属性を追加するか、命名規則を使用して、名前からスコープを識別できるようにします。

次に、バインディング規則を正しくセットアップします。例えば

this.kernel.Bind(x => x
    .FromThisAssembly()
    .SelectAllClasses()
    .WithAttribute<SingletonAttribute>()
    .BindAllInterfaces()
    .Configure(binding => binding.InSingletonScope());

this.kernel.Bind(x => x
    .FromThisAssembly()
    .SelectAllClasses()
    .WithAttribute<TransientAttribute>()
    .BindAllInterfaces());
于 2012-05-23T14:39:53.013 に答える