Ninject InSingletonScope创建多个实例

时间:2015-11-25 13:04:32

标签: c# dependency-injection singleton ninject

我有一个非常简单的测试项目,我尝试告诉ninject我的ILoader实例应该是一个单例。无论我做什么,它都会创建它的多个实例。

简单的界面。

public interface ILoader
{
    IEnumerable<int> Get();
}

用于测试目的的实施

public class TestLoader : ILoader
{
    private IEnumerable<int> _Datasource;

    public void Set(IEnumerable<int> enumerable)
    {
        _Datasource = enumerable;
    }
    public IEnumerable<int> Get()
    {
        return _Datasource;
    }
}

取决于它的类

public class TestClass
{
    private ILoader _loader;
    public TestClass(ILoader loader)
    {
        _loader = loader;
    }

    public void Init()
    {
        foreach (var i in _loader.Get())
            Console.WriteLine(i);
    }
}

模块

public class TestModule : NinjectModule
{
    public override void Load()
    {
        Bind<ILoader>().To<TestLoader>();
        Bind<TestLoader>().ToSelf().InSingletonScope();
    }
}

然后运行它。

class Program
{
    static void Main(string[] args)
    {
        var kernel = new StandardKernel(new TestModule());

        var ds = new List<int> { 1, 2 };
        kernel.Get<TestLoader>().Set(ds);

        var tc = kernel.Get<TestClass>();
        tc.Init();
        Console.ReadLine();
    }
}

这里我想用testdata预加载我的加载器,ninject应该将同一个加载器注入我的TestClass。但是,它会创建一个新实例,而这并不是理想的行为。

我想有办法解决这个问题。但那么InSingletonScope的目的是什么?我不能告诉ninject我想要一个且只有一个ILoader实例。

1 个答案:

答案 0 :(得分:1)

您应该使用构造函数注入(请参阅this question),而不是使用Set方法:

public class TestLoader : ILoader
{
    private IEnumerable<int> _Datasource;

    public TestLoader(IEnumerable<int> enumerable)
    {
        _Datasource = enumerable;
    }
    public IEnumerable<int> Get()
    {
        return _Datasource;
    }
}

接下来是你如何注册并解决它:

static void Main(string[] args)
{
    var kernel = new StandardKernel();

    var ds = new List<int> { 1, 2 };

    kernel
        .Bind<ILoader>()
        .To<TestLoader>()
        .InSingletonScope()
        .WithConstructorArgument("enumerable", ds);

    var tc1 = kernel.Get<TestClass>();
    var tc2 = kernel.Get<TestClass>();
    tc1.Init();
    tc2.Init();

    Console.ReadLine();
}

在此示例中,TestClass的两个实例将获得注入其中的TestLoader的相同实例。

如果由于某种原因你不想使用构造函数注入而你想保留Set方法,你可以这样做:

static void Main(string[] args)
{
    var kernel = new StandardKernel();

    var ds = new List<int> { 1, 2 };

    kernel
        .Bind<ILoader>()
        .To<TestLoader>()
        .InSingletonScope();


    ((TestLoader)kernel.Get<ILoader>()).Set(ds);

    var tc1 = kernel.Get<TestClass>();
    var tc2 = kernel.Get<TestClass>();
    tc1.Init();
    tc2.Init();

    Console.ReadLine();
}