Search code examples
dependency-injectionsimple-injector

SimpleInjector - Register a type for all it's interfaces


Is it possible to register a type for all it's implementing interfaces? E.g, I have a:

public class Bow : IWeapon
{

    #region IWeapon Members

    public string Attack()
    {
        return "Shooted with a bow";
    }

    #endregion
}

public class HumanFighter 

{
    private readonly IWeapon weapon = null;
    public HumanFighter(IWeapon weapon)
    {
        this.weapon = weapon;
    }

    public string Fight()
    {

        return this.weapon.Attack();
    }

}

    [Test]
    public void Test2b()
    {
        Container container = new Container();
        container.RegisterSingle<Bow>();
        container.RegisterSingle<HumanFighter>();

        // this would match the IWeapon to the Bow, as it
        // is implemented by Bow
        var humanFighter1 = container.GetInstance<HumanFighter>(); 

        string s = humanFighter1.Fight();
    }

Solution

  • It completely depends on your needs, but typically you need to use the Container's non-generic registration method. You can define your own LINQ queries to query the application's metadata to get the proper types, and register them using the non-generic registration methods. Here's an example:

    var weaponsAssembly = typeof(Bow).Assembly;
    
    var registrations =
        from type in weaponsAssembly.GetExportedTypes()
        where type.Namespace.Contains(".Weapons")
        from service in type.GetInterfaces()
        select new { Service = service, Implementation = type };
    
    foreach (var reg in registrations)
    {
        container.Register(reg.Service, reg.Implementation);
    }
    

    If you need to batch-register a set of implementations, based on a shared generic interface, you can use the RegisterManyForOpenGeneric extension method:

    // include the SimpleInjector.Extensions namespace.
    
    container.RegisterManyForOpenGeneric(typeof(IValidator<>),
        typeof(IValidator<>).Assembly);
    

    This will look for all (non-generic) public types in the supplied assembly that implement IValidator<T> and registers each of them by their closed-generic implementation. If an type implements multiple closed-generic versions of IValidator<T>, all versions will be registered. Take a look at the following example:

    interface IValidator<T> { }
    class MultiVal1 : IValidator<Customer>, IValidator<Order> { }
    class MultiVal2 : IValidator<User>, IValidator<Employee> { }
    
    container.RegisterManyForOpenGeneric(typeof(IValidator<>),
        typeof(IValidator<>).Assembly);
    

    Assuming the given interface and class definitions, the shown RegisterManyForOpenGeneric registration is equivalent to the following manual registration:

    container.Register<IValidator<Customer>, MultiVal1>();
    container.Register<IValidator<Order>, MultiVal1>();
    container.Register<IValidator<User>, MultiVal2>();
    container.Register<IValidator<Employee>, MultiVal2>();
    

    It would also be easy to add convenient extension methods. Take for instance the following extension method that allows you to register a single implementation by all its implemented interfaces:

    public static void RegisterAsImplementedInterfaces<TImpl>(
        this Container container)
    {
        foreach (var service in typeof(TImpl).GetInterfaces())
        {
            container.Register(service, typeof(TImpl));
        }
    }
    

    It can be used as follows:

    container.RegisterAsImplementedInterfaces<Sword>();