装饰图案与结构图2.6

时间:2012-03-05 17:40:17

标签: .net inversion-of-control structuremap

我正在使用StructureMap 2.6并尝试使用装饰器模式:

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

这很好用,但是我的LoggingBusRefTranslator有一个需要解析的依赖项,所以我想要StructureMap来构建它。我只是无法弄清楚正确的路线和大多数我可以找到的丰富的例子使用旧的语法。

2 个答案:

答案 0 :(得分:3)

我已经通过编写以下扩展方法解决了这个问题。优点是配置的语法更简单,并且自动注入装饰器的依赖关系而不必在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;
        }
    }

答案 1 :(得分:2)

我设法通过将我的装饰器的所有依赖项移动到构造函数依赖项并使用EnrichWith扩展的替代形式来解决这个问题:

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