Reputation: 45135
Using Ninject, I have an interface that I want to bind to single instance of a concrete implementation. For example:
public interface IFoo { //... }
public class Foo { //... }
Now normally, I'd just bind something like this like so:
kernel.Bind<IFoo>().To<Foo>().InSingletonScope();
But, I need to add parameters to the constructor for Foo
. Normally, again, that wouldn't be too much of a problem (I think):
kernel.Bind<IFoo>()
.To<Foo>()
.InSingletonScope()
.WithConstructorArgument("bar", myBar);
Now the problem is that I can't know the value of myBar
at the time I set up all my bindings. I need to defer that until the first time I need an IFoo
(and note, in reality I have several arguments to pass). So what I need is a singleton, that will be lazy initialized on first use and only gets arguments at that point.
What's the best way to approach this? I'm assuming something with Factory is probably the solution, but I don't quite see the right way to do this. I don't want to create a new Foo
every time.
Upvotes: 2
Views: 535
Reputation: 26280
Given the other two answers, I could be completely missing the point of the question, but why would not something as simple as this work for you:
kernel.Bind<IFoo>().ToMethod(x => CreateFoo()).InSingletonScope();
CreateFoo
will be responsible for constructing your single object with whatever set of parameters that you need. By the time CreateFoo
is called you should already know what the parameters are.
Upvotes: 0
Reputation: 3289
You can use the Factory extension.
public interface IFooFactory
{
IFoo CreateFoo(string bar);
IFoo CreateFoo();
}
public interface IFoo
{
string Bar { get; set; }
}
public class Foo : IFoo
{
public string Bar { get; set; }
public Foo(string bar)
{
Bar = bar;
}
}
kernel.Bind<IFoo>().To<Foo>().InSingletonScope();
kernel.Bind<IFooFactory>().ToFactory();
IFoo foo1 = fooFactory.CreateFoo("myBar");
IFoo foo2 = fooFactory.CreateFoo("myDifferentBar"); // value is basically ignored here
IFoo foo3 = fooFactory.CreateFoo();
This will always return the same instance of Foo. Of course if you call the paremeterless method first it will result in an exception.
Upvotes: 1
Reputation: 1285
As in my comment above. the real problem is that you may not have the construction parameters when you need Foo. In this pattern you can Bind all your interfaces as you please and call IInitialiser.Initialise when you are ready (obvs you need to keep a reference or make it static).
Foo will throw an exception if you call it before its been properly set up
IFoo remains unchanged
IInitialiser implementations can be tweaked to poll a DB or respond to events or whatever suits your late configuration senario best
using System;
namespace UnitTestProject3
{
public interface IFoo
{
int GetAllTheFoo();
}
public interface IInitialiser
{
void Initialise(int x);
int GetX();
bool IsReady { get; }
}
public class Foo : IFoo
{
private bool isInitalised;
private int x;
private IInitialiser i;
public Foo(IInitialiser i)
{
this.isInitalised = false;
this.i = i;
}
protected void Init()
{
if (this.isInitalised)
{
return;
}
else if (i.IsReady)
{
x = i.GetX();
this.isInitalised = true;
return;
}
else
{
throw new Exception("you have not set x");
}
}
public int GetAllTheFoo()
{
Init();
return x;
}
}
}
Upvotes: 1