Шаблон декоратора со структурной картой 2.6 - PullRequest
3 голосов
/ 05 марта 2012

Я использую StructureMap 2.6 и пытаюсь использовать шаблон декоратора:

        For<IBusRefTranslator>().Use<BusRefTranslator>()
            .EnrichWith((x) => new LoggingBusRefTranslator(x))
            .Ctor<string>("connectionString").Is(connectionString);

Это работает отлично, однако мой LoggingBusRefTranslator имеет зависимость, которую необходимо разрешить, поэтому я хочу, чтобы StructureMap его построил. Я просто не могу найти правильный путь, и большинство примеров обогащения, которые я могу найти, используют старый синтаксис.

Ответы [ 2 ]

3 голосов
/ 05 сентября 2012

Я решил это сам, написав следующий метод расширения.Преимущество заключается в том, что синтаксис конфигурации проще и что зависимости декоратора автоматически вводятся, а не приходится разбираться с ними самостоятельно в выражении 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;
        }
    }
2 голосов
/ 06 марта 2012

Мне удалось решить эту проблему, переместив все мои зависимости для моего декоратора в зависимости конструктора и используя альтернативную форму расширения EnrichWith:

        For<IBusRefTranslator>().Use<BusRefTranslator>()
            .EnrichWith<IBusRefTranslator>((c, x) => new LoggingBusRefTranslatorDecorator(x, c.GetInstance<IFusionLogService>()))
            .Ctor<string>("connectionString").Is(connectionString);
...