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;
        }
    }
}

在这个测试用例中,图书馆由RegistryThing1IThing1类表示。库的用户是测试夹具,该Spike.SetUp()方法显示了我们希望库用户编写的理想代码(他们将传递包含 dll 的路径而不是新建Registry对象)。

使用编写的代码,Thing1多次获取服务会Spike.GetThing1AndThing2()表现出所需的单例行为。Thing1通过其发布的接口多次获取服务Spike.GetIThing1AndIThing2()不会表现出单例行为,而是构造两个单独的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 回答