IoC Challenge – Multiple interfaces to the same singleton instance

I have an IoC challenge that I am currently trying to work through. I have a series of classes that implement more than one interface, with the lifetime of the class needing to be a singleton, and I really don’t like the idea of falling back on custom instantiation code along with potentially custom lifetime management code to make this work.

Sound confusing? Here is the model I am trying for. First the interfaces I will be looking asking the container for.

public interface IInitializable
{
  void Init();
}

public interface IStartable
{
  void Start();
  void Stop();
}

Then a couple of classes implementing the interfaces.

class ServiceOne : IInitializable, IStartable
{
  public void Init()
  {
    Console.WriteLine(GetType().Name + ".Init() " + GetHashCode().ToString());
  }
  public void Start()
  {
    Console.WriteLine(GetType().Name + ".Start() " + GetHashCode().ToString());
  }
  public void Stop()
  {
    Console.WriteLine(GetType().Name + ".Stop() " + GetHashCode().ToString());
  }
}

class ServiceTwo : IInitializable, IStartable
{
  public void Init()
  {
    Console.WriteLine(GetType().Name + ".Init() " + GetHashCode().ToString());
  }
  public void Start()
  {
    Console.WriteLine(GetType().Name + ".Start() " + GetHashCode().ToString());
  }
  public void Stop()
  {
    Console.WriteLine(GetType().Name + ".Stop() " + GetHashCode().ToString());
  }
}

Not the worlds most ambitious code, to be sure, but it does demonstrate the model well. Of course this code is pointless without how I want to use it, so here is a sample of referencing.

foreach (IInitializable item in container.GetAllInstances<IInitializable>())
{
  item.Init();
}

foreach (IStartable item in container.GetAllInstances<IStartable>())
{
  item.Start();
  item.Stop();
}

Once more a very contrived example. All in all, I expect there to be 2 physical instances (say object A and object B), and two mappings per unique interface. So there should be in the container 4 types registered to those two physical instances.

There are two easy ways to do this now. First is bind the interfaces directly to a pre-created instance. However, this means that the instance cannot be built up by the container because it is instantiated prior to type registration being complete. Here is an example using StructureMap.

var container = new Container();
var serviceOne = new ServiceOne();
var serviceTwo = new ServiceTwo();

container.Configure(x =>
  {
    x.ForRequestedType<IInitializable>().AddInstances(y =>
    {
      y.IsThis(serviceOne);
      y.IsThis(serviceTwo);
    });

    x.ForRequestedType<IStartable>().AddInstances(y =>
    {
      y.IsThis(serviceOne);
      y.IsThis(serviceTwo);
    });
  });

The second option is to bind to a function. Here is an example using Ninject from the Ninject groups discussion.

Bind<IInitializable>().To<ServiceOne>().InSingletonScope();
Bind<IStartable>().ToMethod>(context=> context.kernel.Get<ServiceOne>());

The issue with the second model is that the interfaces need to be aware of each other and the concrete class.

What I am looking to do is more like this.

container.Configure(x =>
    { //  these would be registered in one registry
        x.ForRequestedType<IInitializable>().AddSingleton<ServiceOne>().WithName("One");
        x.ForRequestedType<IInitializable>().AddSingleton<ServiceTwo>().WithName("Two");
        //  these would be registered in another registry
        x.ForRequestedType<IStartable>().AddSingleton<ServiceOne>().WithName("One");
        x.ForRequestedType<IStartable>().AddSingleton<ServiceTwo>().WithName("Two");
    });

That is some pseudo code using StructureMap. My challenge to the world IoC gurus out there, is how to do this using either Ninject, StructureMap, or Unity. I do realize that there are other IoC containers out there, however these are the three I have the most familiarity with. I would be open to see how it is done in the other containers.

Related

comments powered by Disqus