不同的构造函数参数装饰 [英] Decorators with different constructor arguments
问题描述
使用温莎城堡,我想创建记录一个整数的类。但我想几次与其他类装饰。我可以看到这是如何工作,如果涉及的所有混凝土具有依赖性,可以解决,但这里并非如此。考虑下面的代码:
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
,这时候真的会在电流$ C复制$ C>上下文的
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屋!