具有不同构造函数参数的装饰器
使用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
,从而将参数传递给子依赖项。
要将此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());
使用DefaultKernel
和WindsorContainer
的无参数构造函数时, NotSupportedProxyFactory
和DefaultComponentInstaller
是默认值。
完成后,上面的代码将在工厂用于创建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);
希望这有助于他人!