具有不同构造函数参数的装饰器

使用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().ImplementedBy()); container.Register(Component.For().ImplementedBy()); 

解决IRecorder永远不会在这里工作,因为ModelUpdatingRecorder具有非可选的依赖性。 我不能使用静态依赖项,因为在编译时不知道seed

有没有办法在运行时指定seed参数并使装饰仍然有效?

此代码示例是我的方案的简化,但想法是相同的。 我有装饰器,最低的装饰器依赖于提供给它的特定值/实例。

你可以将种子包装在一个接口( 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; } 

这个解决方案能满足您的需求吗?

我找到了一个解决方案,我认为应该这样做。 在Windsor的内部, DefaultDependencyResolver有一个方法,用于解析名为IRecorder子依赖项(例如上面的IRecorder的修饰实例)。 它调用它来创建在解析依赖项(即构造函数的参数)时使用的新上下文。 方法是:

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

CreationContext构造函数中的false参数是propagateInlineDependencies ,当为true时,将复制current上下文的AdditionalArguments ,从而将参数传递给子依赖项。

要将此falsetrue ,请创建一个派生自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()); 

使用DefaultKernelWindsorContainer的无参数构造函数时, NotSupportedProxyFactoryDefaultComponentInstaller是默认值。

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

 // during type registration/bootstrapping container.AddFacility(); container.Register(Component.For().ImplementedBy()); container.Register(Component.For().ImplementedBy()); container.Register(Component.For().AsFactory()); 

IRecorderFactory在哪里:

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

然后这将按预期工作:

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

希望这有助于他人!