不同的构造函数参数装饰 [英] Decorators with different constructor arguments

查看:101
本文介绍了不同的构造函数参数装饰的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用温莎城堡,我想创建记录一个整数的类。但我想几次与其他类装饰。我可以看到这是如何工作,如果涉及的所有混凝土具有依赖性,可以解决,但这里并非如此。考虑下面的代码:

Using Castle Windsor, I'd like to create a class that records an integer. But I'd like to decorate it several times with other classes. I can see how this works if all concretes involved have dependencies that can be resolved, but that's not the case here. Consider this code:

public interface IRecorder
{
    void Add(int value);
}

public class NotifyingRecorder : IRecorder
{
    readonly IRecorder decoratedRecorder;

    public NotifyingRecorder(IRecorder decoratedRecorder)
    {
        this.decoratedRecorder = decoratedRecorder;
    }

    public void Add(int value)
    {
        decoratedRecorder.Add(value);
        System.Console.WriteLine("Added " + value);
    }
}

public class ModelUpdatingRecorder : IRecorder
{
    int seed;

    public ModelUpdatingRecorder(int seed)
    {
        this.seed = seed;
    }

    public void Add(int value)
    {
        seed += value;
    }
}

和与注册:

container.Register(Component.For<IRecorder>().ImplementedBy<NotifyingRecorder>());
container.Register(Component.For<IRecorder>().ImplementedBy<ModelUpdatingRecorder>());



解决一个 IRecorder 将永远不会在这里工作,因为 ModelUpdatingRecorder 具有非可选的依赖。我不能使用,因为种子在编译时是不知道一个静态的依赖关系。

Resolving an IRecorder will never work here, since ModelUpdatingRecorder has a non-optional dependency. I cannot use a static dependency since seed is not known at compile-time.

有没有指定的方式在种子参数在运行时有装修还是工作?

Is there a way to specify the seed parameter at runtime and have the decoration still work?

此代码示例是一个简化我的方案,但这个想法是一样的。我有装饰,并且最低的一个依赖于一个特定的值/实例将被提供给它。

推荐答案

我发现,我认为这是应该做的方式解决。倒在温莎的内部结构的 DefaultDependencyResolver 有它用来解析子依赖(如装饰实例的方法 IRecorder 以上)称为 RebuildContextForParameter 。它调用它来创建新的上下文解决依赖(即参数构造函数)时使用。其方法是:

I've found a solution that I believe is the way this should be done. Down in the innards of Windsor the DefaultDependencyResolver has a method it uses to resolve sub-dependencies (such as a decorated instance of IRecorder above) called RebuildContextForParameter. It calls this to create a new context to use when resolving the dependency (i.e. the parameter to the constructor). The method is:

/// <summary>This method rebuild the context for the parameter type. Naive implementation.</summary>
protected virtual CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
{
    if (parameterType.ContainsGenericParameters)
    {
        return current;
    }

    return new CreationContext(parameterType, current, false);
}



参数在 CreationContext 构造器是 propagateInlineDependencies ,这时候真的会在电流上下文的 AdditionalArguments ,从而传递下来的参数子的依赖关系。

The false parameter in CreationContext constructor is propagateInlineDependencies, which when true will copy over the current context's AdditionalArguments, thereby passing down the parameters to the sub-dependencies.

要翻转这个真正,创建从 DefaultDependencyResolver 的新类:

To flip this false to true, create a new class that derives from DefaultDependencyResolver:

public class DefaultDependencyResolverInheritContext : DefaultDependencyResolver
{
    protected override CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
    {
        if (parameterType.ContainsGenericParameters)
        {
            return current;
        }

        return new CreationContext(parameterType, current, true);
    }
}



然后使用创建的温莎容器时:

Then use that when creating the Windsor container:

var kernel = new DefaultKernel(
                 new DefaultDependencyResolverInheritContext(), 
                 new NotSupportedProxyFactory());
var container = new WindsorContainer(kernel, new DefaultComponentInstaller());



NotSupportedProxyFactory DefaultComponentInstaller 使用时 DEFAULTKERNEL 和 WindsorContainer 是默认值。

The NotSupportedProxyFactory and DefaultComponentInstaller are the defaults when using the parameter-less constructors for DefaultKernel and WindsorContainer.

当完成后,上面的代码将在一个工厂用于创建工作的 IRecorder ,即:

When done, the code above will work when a factory is used to create an IRecorder, i.e.:

// during type registration/bootstrapping
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IRecorder>().ImplementedBy<NotifyingRecorder>());
container.Register(Component.For<IRecorder>().ImplementedBy<ModelUpdatingRecorder>());
container.Register(Component.For<IRecorderFactory>().AsFactory());



其中, IRecorderFactory 是:

public interface IRecorderFactory
{
    IRecorder Create(int seed);
}



那么这将如预期:

Then this will work as expected:

IRecorderFactory recorderFactory = container.Resolve<IRecorderFactory>();
IRecorder recorder = recorderFactory.Create(20);
recorder.Add(6);



希望帮助别人!

Hopefully that helps others!

这篇关于不同的构造函数参数装饰的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆