2

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.

asked Apr 9, 2015 at 19:47
9
  • can you not bind at any point in the program? Commented Apr 9, 2015 at 19:55
  • @Ewan: Not without passing the kernel around, which I don't want to do. Unless I'm missing something. Commented Apr 9, 2015 at 19:57
  • it seems to me that your problem is 'the first time you need an IFoo' when you are talking about DI is not determinable. so how will you know that you know the construction parameters at that point? Commented Apr 9, 2015 at 19:59
  • no i agree passing the kernal around isnt a great solution. but you have an odd case Commented Apr 9, 2015 at 20:00
  • 1
    ooo ive got a better one. have Foo take a IInitializer constructor. when you call its method it calls the initalizer to try and get the required parameters and initialize itsself. you code can set these parameters on the initaliser whenever they become available. that way you avoid adding extra Foo specific stuff to IFoo Commented Apr 9, 2015 at 20:12

3 Answers 3

1

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;
 }
 }
}
answered Apr 9, 2015 at 20:44
Sign up to request clarification or add additional context in comments.

Comments

1

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.

answered Apr 15, 2015 at 10:45

Comments

0

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.

answered Apr 23, 2015 at 9:47

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.