Search code examples
c#inversion-of-controlunity-container

Unity: tell container to always use specific implementation of an interface when registering a type


I keep running into this scenario: suppose I have interface IFoo and several implementations, like RedFoo : IFoo and BlackFoo : IFoo. I then have classes that take IFoo in the constructor:

class BlackFooUser
{
   public BlackFooUser(IFoo foo, other_parameters_here) {...}
}

class RedFooUser
{
   public RedFooUser(IFoo foo, other_parameters_here) {...}
}

How do I tell the container to resolve all other parameters as usual, but always use BlackFoo when constructing BlackFooUser, and always use RedFoo when constructing RedFooUser? I know I can use ParameterOverride when calling Resolve(), but I want it to be the same whenever a Red/BlackFooUser is resolved, so this should go into RegisterType or RegisterFactory.

I can do something like

container.RegisterFactory<RedFooUser>(c=>new RedFooUser(c.Resolve<RedFoo>(), other_parameters_here));

but this is quite verbose, and this will have to change every time I add new parameters.

Is there a better way?

UPDATE I am specifically looking to do this through container registrations, without modifying the classes involved. There are multiple reasons for that, but it boils down to this:

  • Encoding dependency information in the classes violates separation of concerns
  • It usually scales poorly in case of many classes and many dependencies
  • It puts limits to how the classes can be composed
  • It restricts me to classes that I own the source to and can modify at will

Solution

  • I submitted an issue to UnityContainer repo, and the response by Eugene Sadovoy pushed me towards this answer.

    To avoid an infinite loop, one can register the default factory as named registration, and invoke it from the default, unnamed factory, along the lines of (sorry, I changed the names a little compared to the question):

    container
      .RegisterType<SpecialFooUser>("stdreg")
      .RegisterFactory<SpecialFooUser>(
          c => c.Resolve<SpecialFooUser>("stdreg", 
            new DependencyOverride<IFoo>(c.Resolve<SpecialFoo>()))
        );
    

    This works, but looks quite verbose, so I wrote a few extension methods and classes (~100 lines of code total) to make it less verbose and more expressive:

    container.Register(
      new CustomFactory<SpecialFooUser>()
        .DependencyOverride<IFoo, SpecialFoo>());
    

    The complete source code is on GitHub: https://github.com/ikriv-samples/UnityResolveOverrideFactory