Reputation: 3059
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.
Upvotes: 1
Views: 3979
Reputation: 27861
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();
}
Upvotes: 1