I think @atomaras might have a good point about your abstraction, although I think it would be fine when you only use this information inside your Composition Root, since your Composition Root is already aware of every implementation in the system.
I think there are a few ways to get to this information:
Use the
DecoratorPredicateContext
information that is supplied to theRegisterDecorator
extension method:var typeMapping = new Dictionary<Type, Type>(); container.RegisterDecorator(typeof(IInstructionHandler<>), typeof(FakeDecorator<>), c => { typeMapping[c.ServiceType] = c.ImplementationType; // or perhaps even use c.AppliedDecorators property to see which decorators // are applied. // return false to prevent the decorator from being applied. return false; });
You can make a fake registration that Simple Injector will call for every
IInstructionHandler<T>
in the system, but you prevent it from being applied by supplying a predicate that will always returnfalse
. You can use the info supplied by Simple Injector in theDecoratorPredicateContext
to find out what the actual ImplementationType is.
Alternatively, you can inject an DecoratorContext
instance (v2.6 and up) into the top most decorator (as explained here). The DecoratorContext
contains the same information as the DecoratorPredicateContext
does, but this object will automatically be injected by Simple Injector into a decorator that depends on. It allows you to make the decision inside a decorator, which might be very convenient in your case.
Add an an
IDecorator
abstraction to the system to allow traversing the decorator chain.By letting each decorator implement a
IDecorator
interface that allows access to the decoratee (just as done here) you can traverse the decorator chain and find the actual implementation type:public interface IDecorator { object Decoratee { get; } } public static class DecoratorHelpers { public static IEnumerable<object> GetDecoratorChain(IDecorator decorator) { while (decorator != null) { yield return decorator; decorator = decorator.Decoratee as IDecorator; } } }
You can implement your decorators with this interface as follows:
public class SomeDecorator<T> : IInstructionHandler<T>, IDecorator { private readonly IInstructionHandler<T> decoratee; public SomeDecorator(IInstructionHandler<T> decoratee) { this.decoratee = decoratee; } object IDecorator.Decoratee { get { return this.decoratee; } } }
When you implemented this interface on all your decorators, you will be able to do this:
var implementationTypes = from handler in container.GetAllInstances<IInstructionHandler<RenderWord>>() let mostInnerDecorator = DecoratorHelpers.GetDecoratorChain(handler as IDecorator).LastOrDefault() let implementation = mostInnerDecorator != null ? mostInnerDecorator.Decoratee : handler select implementation.GetType()
Register a list of
Registration
instances in one of theRegisterAll
overloads, since theRegistration
object knows about the actual implemenation type.But instead of point 3, you might as well use the list of implemenation types that you used to create those registrations:
typeMapping[serviceType] = implementationTypes; container.RegisterAll(serviceType, implementationTypes);
Simple Injector will resolve the registered implementations always in the same order as they are registered (this is guaranteed). So when you resolve a collection of things, you will already have the list of implementations that is layed out in the same order.