1

I have a very simple test project where I try tell ninject that my ILoader instance should be a singleton. No matter what I do it creates multiple instances of it.

Simple interface.

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

Implementation for test purpose

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

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

Class that depends on it

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

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

Module

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

And run it.

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

Here I want to preload my loader with testdata and the ninject should inject that very same loader into my TestClass. However it creates a new instance which is not really the desired behaviour.

I guess there are ways to work around this. But then what is the purpose of InSingletonScope? Shouldnt I be able to tell ninject that I want one and only one instance of ILoader.

Evelie
  • 2,919
  • 2
  • 14
  • 21

1 Answers1

1

Instead of having the Set method, you should use constructor injection (see this question) like this:

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

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

And then here is how you would register it and resolve it:

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

In this example, the two instance of TestClass will get the same instance of TestLoader injected into them.

If for some reason you don't want to use constructor injection and you want to keep the Set method, you can do this:

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();
}
Community
  • 1
  • 1
Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62
  • The test is not really to load the datasource. It was just there to repsent some call I would like to do on my class before or after it has been injected. But it seems that if i do kernel Get on interface and then cast to my class it indeed returns a single instance. Why does it create a new instance if i Get on the class instead of the interface? Is this really the intended behaviour? Nevertheless your last example is what im trying to do here. Thanks – Evelie Nov 26 '15 at 08:14