From 016eabb1a103c74c11e650736e2dd66aeabba531 Mon Sep 17 00:00:00 2001 From: Antony Male Date: Thu, 11 Sep 2014 12:55:29 +0100 Subject: [PATCH] Fix bug where unbound generics weren't being propagated --- Stylet/StyletIoC/StyletIoCContainer.cs | 31 +++++++++++++++++--------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/Stylet/StyletIoC/StyletIoCContainer.cs b/Stylet/StyletIoC/StyletIoCContainer.cs index dd07cdd..5224a9c 100644 --- a/Stylet/StyletIoC/StyletIoCContainer.cs +++ b/Stylet/StyletIoC/StyletIoCContainer.cs @@ -15,6 +15,8 @@ namespace StyletIoC // Needs to be public, or FactoryAssemblyName isn't visible public class StyletIoCContainer : IContainer, IRegistrationContext { + private readonly StyletIoCContainer parent; + /// /// Name of the assembly in which abstract factories are built. Use in [assembly: InternalsVisibleTo(StyletIoC.FactoryAssemblyName)] to allow factories created by .ToAbstractFactory() to access internal types /// @@ -31,8 +33,6 @@ namespace StyletIoC /// private readonly ConcurrentDictionary getAllRegistrations = new ConcurrentDictionary(); - private readonly Dictionary> parentUnboundGenerics; - /// /// Maps a [type, key] pair, where 'type' is an unbound generic (something like IValidator{}) to something which, given a type, can create an IRegistration for that type. /// So if they've bound an IValidator{} to a an IntValidator, StringValidator, etc, and request an IValidator{string}, one of the UnboundGenerics here can generatr a StringValidator. @@ -72,15 +72,15 @@ namespace StyletIoC // it's always created by a child, the parent will never get a cached copy. This might get addressed at some point, but the complexity might not // be worth it (especially for such a rarely-used feature). + this.parent = parent; this.registrations = DelegatingDictionary.Create(parent.registrations, registration => registration.CloneToContext(this)); - this.parentUnboundGenerics = parent.unboundGenerics; this.builderUppers = DelegatingDictionary.Create(parent.builderUppers); } internal StyletIoCContainer() { + this.parent = null; this.registrations = DelegatingDictionary.Create(); - this.parentUnboundGenerics = null; this.builderUppers = DelegatingDictionary.Create(); } @@ -273,6 +273,22 @@ namespace StyletIoC return true; } + private List UnboundGenericsFromSelfAndParent(TypeKey typeKey) + { + List unboundGenerics; + if (this.parent != null) + unboundGenerics = this.parent.UnboundGenericsFromSelfAndParent(typeKey); + else + unboundGenerics = new List(); + + List outUnboundGenerics; + if (this.unboundGenerics.TryGetValue(typeKey, out outUnboundGenerics)) + unboundGenerics.AddRange(outUnboundGenerics); + + return unboundGenerics; + + } + /// /// Given a generic type (e.g. IValidator{T}), tries to create a collection of IRegistrations which can implement it from the unbound generic registrations. /// For example, if someone bound an IValidator{} to Validator{}, and this was called with Validator{T}, the IRegistrationCollection would contain a Validator{T}. @@ -290,13 +306,8 @@ namespace StyletIoC Type unboundGenericType = type.GetGenericTypeDefinition(); - var unboundGenerics = new List(); - List outUnboundGenerics; var unboundTypeKey = new TypeKey(unboundGenericType, typeKey.Key); - if (this.parentUnboundGenerics != null && this.parentUnboundGenerics.TryGetValue(unboundTypeKey, out outUnboundGenerics)) - unboundGenerics.AddRange(outUnboundGenerics); - if (this.unboundGenerics.TryGetValue(unboundTypeKey, out outUnboundGenerics)) - unboundGenerics.AddRange(outUnboundGenerics); + var unboundGenerics = this.UnboundGenericsFromSelfAndParent(unboundTypeKey); foreach (var unboundGeneric in unboundGenerics) {