Я решил это сам, написав следующий метод расширения.Преимущество заключается в том, что синтаксис конфигурации проще и что зависимости декоратора автоматически вводятся, а не приходится разбираться с ними самостоятельно в выражении new
.Синтаксис для украшения объекта был бы следующим:
For<IBusRefTranslator>().Use<BusRefTranslator>()
.Decorate().With<LoggingBusRefTranslatorDecorator>(); // dependencies and decoratee automatically injected
Класс расширения:
public static class StructureMapExtensions
{
/// <summary>
/// Configures the defined instance to be wrapped by an instance of another decorator type
/// </summary>
public static DecorateConfig<T> Decorate<T>(this SmartInstance<T> instance)
{
return new DecorateConfig<T>(instance);
}
public class DecorateConfig<T>
{
private readonly SmartInstance<T> _instance;
internal DecorateConfig(SmartInstance<T> instance)
{
_instance = instance;
}
private static IEnumerable<Type> GetTypeAndAllBaseTypes(Type t)
{
if (t == typeof(object))
yield break;
yield return t;
foreach (var @base in t.GetInterfaces().Union(GetTypeAndAllBaseTypes(t.BaseType)))
yield return @base;
}
private static string FindArgumentNameForWrappedInner(Type decoratorType)
{
foreach (var t in GetTypeAndAllBaseTypes(typeof(T)))
{
var argumentName = new Plugin(decoratorType).FindArgumentNameForType(t, CannotFindProperty.Ignore);
if (argumentName != null)
return argumentName;
}
throw new ConfigurationErrorsException("Type " + decoratorType + " has no constructor arguments of type " + typeof(T));
}
public SmartInstance<TDecorator> With<TDecorator>()
{
var decoratorInstance = new SmartInstance<TDecorator>();
_instance.EnrichWith((context, inner) => decoratorInstance
.WithCtorArg(FindArgumentNameForWrappedInner(typeof(TDecorator))).EqualTo(inner)
.Build(typeof (TDecorator), (BuildSession) context));
return decoratorInstance;
}
}