使用Castle Windsor,我想创建一个记录整数的类。但是我想和其他课程一起装饰几次。如果所涉及的所有混凝土都具有可以解决的依赖关系,我可以看到它是如何工作的,但这不是这里的情况。请考虑以下代码:
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
具有非可选的依赖关系。我不能使用静态依赖,因为在编译时不知道seed
。
有没有办法在运行时指定seed
参数并使装饰仍然有效?
此代码示例是我的方案的简化,但想法是一样的。我有装饰器,最低的装饰器依赖于要提供给它的特定值/实例。
答案 0 :(得分:0)
您可以将种子包装在界面(ISeedHolder
?)中,并以单身生活方式注册。然后使用ModelUpdatingRecorder
中的接口而不是raw int。除非您的种子可能需要并行化,否则应该允许您在构建ModelUpdatingRecorder
时设置种子并解决它
public interface ISeedHolder
{
int Seed {get;set;}
}
public class ModelUpdatingRecorder : IRecorder
{
int seed;
public ModelUpdatingRecorder(ISeedHolder seedHolder)
{
this.seed = seedHolder.Seed;
}
这个解决方案能满足您的需求吗?
答案 1 :(得分:0)
我找到了一个我认为应该这样做的解决方案。在温莎的内部,DefaultDependencyResolver
有一个方法,用于解析名为RebuildContextForParameter
的子依赖关系(例如上面IRecorder
的修饰实例)。它调用它来创建在解析依赖项(即构造函数的参数)时使用的新上下文。方法是:
/// <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);
}
false
构造函数中的CreationContext
参数为propagateInlineDependencies
,如果为true,则会复制current
上下文AdditionalArguments
,从而传递子依赖的参数。
要将此false
翻转为true
,请创建一个派生自DefaultDependencyResolver
的新类:
public class DefaultDependencyResolverInheritContext : DefaultDependencyResolver
{
protected override CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
{
if (parameterType.ContainsGenericParameters)
{
return current;
}
return new CreationContext(parameterType, current, true);
}
}
然后在创建Windsor容器时使用它:
var kernel = new DefaultKernel(
new DefaultDependencyResolverInheritContext(),
new NotSupportedProxyFactory());
var container = new WindsorContainer(kernel, new DefaultComponentInstaller());
使用NotSupportedProxyFactory
和DefaultComponentInstaller
的无参数构造函数时,DefaultKernel
和WindsorContainer
是默认设置。
完成后,上面的代码将在使用工厂创建IRecorder
时起作用,即:
// 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);
}
然后这将按预期工作:
IRecorderFactory recorderFactory = container.Resolve<IRecorderFactory>();
IRecorder recorder = recorderFactory.Create(20);
recorder.Add(6);
希望能帮到别人!