alexander-l
6/5/2014 - 8:29 AM

DecorateThis.cs

public static class StructureMapDecoratorHelperExtension
{
	public static DecoratorHelper<TTarget> Decorate<TTarget>(this SmartInstance<TTarget> instance)
	{
		return new DecoratorHelper<TTarget>(instance);
	}
}

public class DecoratorHelper<TTarget>
{
	private readonly SmartInstance<TTarget> _instance;

	public DecoratorHelper(SmartInstance<TTarget> instance)
	{
		_instance = instance;
	}

	public DecoratedInstance<TTarget> With<TDecorator>()
	{
		ContextEnrichmentHandler<TTarget> decorator = (ctx, t) =>
		{
			var pluginType = ctx.BuildStack.Current.RequestedType;

			ctx.RegisterDefault(pluginType, t);

			return ctx.GetInstance<TDecorator>();
		};

		_instance.EnrichWith(decorator);

		return new DecoratedInstance<TTarget>(_instance, decorator);
	}
}

public class DecoratedInstance<TTarget>
{
	private readonly SmartInstance<TTarget> _instance;
	private ContextEnrichmentHandler<TTarget> _decorator;

	public DecoratedInstance(
		SmartInstance<TTarget> instance,
		ContextEnrichmentHandler<TTarget> decorator)
	{
		_instance = instance;
		_decorator = decorator;
	}

	public DecoratedInstance<TTarget> AndThen<TDecorator>()
	{
		//Must be captured as a local variable, otherwise the closure's decorator will
		//always be the outer-most decorator, causing a Stack Overflow.
		var previousDecorator = _decorator;

		ContextEnrichmentHandler<TTarget> newDecorator = (ctx, t) =>
		{
			var pluginType = ctx.BuildStack.Current.RequestedType;

			var innerInstance = previousDecorator(ctx, t);

			ctx.RegisterDefault(pluginType, innerInstance);

			return ctx.GetInstance<TDecorator>();
		};

		_instance.EnrichWith(newDecorator);

		_decorator = newDecorator;

		return this;
	}
}