From b59c03430969b8cac3adc10638456f69bb97c922 Mon Sep 17 00:00:00 2001 From: Eugene Sadovoi Date: Fri, 19 Apr 2019 14:53:10 -0400 Subject: [PATCH] New Array resolution --- src/Factories/ArrayResolver.cs | 64 ++++++-- src/Factories/EnumerableResolver.cs | 33 ++--- src/UnityContainer.Registration.cs | 1 + src/UnityContainer.Resolution.cs | 217 ++++++++++++++++++---------- 4 files changed, 207 insertions(+), 108 deletions(-) diff --git a/src/Factories/ArrayResolver.cs b/src/Factories/ArrayResolver.cs index ed8406e7..0f617b53 100644 --- a/src/Factories/ArrayResolver.cs +++ b/src/Factories/ArrayResolver.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Reflection; using Unity.Builder; using Unity.Policy; -using Unity.Registration; using Unity.Resolution; namespace Unity.Factories @@ -12,10 +11,13 @@ namespace Unity.Factories { #region Fields - private static readonly MethodInfo ResolveMethod = - typeof(UnityContainer).GetTypeInfo() - .GetDeclaredMethod(nameof(UnityContainer.GetArray)); + private static readonly MethodInfo ResolverMethod = + typeof(ArrayResolver).GetTypeInfo() + .GetDeclaredMethod(nameof(ArrayResolver.ResolverFactory)); + private static readonly MethodInfo BuiltInMethod = + typeof(ArrayResolver).GetTypeInfo() + .GetDeclaredMethod(nameof(ArrayResolver.BuiltInFactory)); #endregion @@ -27,12 +29,16 @@ namespace Unity.Factories var typeArgument = context.RegistrationType.GetElementType(); var targetType = ((UnityContainer)context.Container).GetTargetType(typeArgument); - // Simple types - var method = (ResolveArray) - ResolveMethod.MakeGenericMethod(typeArgument) - .CreateDelegate(typeof(ResolveArray)); + if (typeArgument != targetType) + { + return ((BuiltInFactoryDelegate)BuiltInMethod + .MakeGenericMethod(typeArgument) + .CreateDelegate(typeof(BuiltInFactoryDelegate)))(targetType); + } - return (ref BuilderContext c) => method(c.Resolve, c.Resolve); + return ((ArrayFactoryDelegate)ResolverMethod + .MakeGenericMethod(typeArgument) + .CreateDelegate(typeof(ArrayFactoryDelegate)))(); }; #endregion @@ -40,14 +46,48 @@ namespace Unity.Factories #region Implementation - + private static ResolveDelegate ResolverFactory() + { +#if NETSTANDARD1_0 || NETCOREAPP1_0 + if (typeof(TElement).GetTypeInfo().IsGenericType) +#else + if (typeof(TElement).IsGenericType) +#endif + { + var definition = typeof(TElement).GetGenericTypeDefinition(); + return (ref BuilderContext c) => ((UnityContainer)c.Container).ResolveArray(c.Resolve, typeof(TElement), definition) + .ToArray(); + } + + return (ref BuilderContext c) => ((UnityContainer)c.Container).ResolveArray(c.Resolve, typeof(TElement)) + .ToArray(); + } + + private static ResolveDelegate BuiltInFactory(Type type) + { +#if NETSTANDARD1_0 || NETCOREAPP1_0 + var info = type.GetTypeInfo(); + if (info.IsGenericType && !info.IsGenericTypeDefinition) +#else + if (type.IsGenericType && !type.IsGenericTypeDefinition) +#endif + { + var definition = type.GetGenericTypeDefinition(); + return (ref BuilderContext c) => ((UnityContainer)c.Container).ComplexArray(c.Resolve, type, definition) + .ToArray(); + } + + return (ref BuilderContext c) => ((UnityContainer)c.Container).ComplexArray(c.Resolve, type) + .ToArray(); + } + #endregion #region Nested Types - - internal delegate object ResolveArray(Func resolve, Func resolveRegistration); + private delegate ResolveDelegate ArrayFactoryDelegate(); + private delegate ResolveDelegate BuiltInFactoryDelegate(Type type); #endregion } diff --git a/src/Factories/EnumerableResolver.cs b/src/Factories/EnumerableResolver.cs index c9c6c631..d56286f9 100644 --- a/src/Factories/EnumerableResolver.cs +++ b/src/Factories/EnumerableResolver.cs @@ -13,11 +13,11 @@ namespace Unity.Factories private static readonly MethodInfo EnumerableMethod = typeof(EnumerableResolver).GetTypeInfo() - .GetDeclaredMethod(nameof(EnumerableResolver.ResolveEnumerable)); + .GetDeclaredMethod(nameof(EnumerableResolver.Resolver)); - private static readonly MethodInfo GenericEnumerable = + private static readonly MethodInfo EnumerableFactory = typeof(EnumerableResolver).GetTypeInfo() - .GetDeclaredMethod(nameof(EnumerableResolver.ResolveGeneric)); + .GetDeclaredMethod(nameof(EnumerableResolver.ResolverFactory)); #endregion @@ -35,18 +35,15 @@ namespace Unity.Factories if (typeArgument.IsGenericType) #endif { - var method = (ResolveEnumerableDelegate) - GenericEnumerable.MakeGenericMethod(typeArgument) - .CreateDelegate(typeof(ResolveEnumerableDelegate)); - - Type type = typeArgument.GetGenericTypeDefinition(); - - return (ref BuilderContext c) => method(ref c, type); + return ((EnumerableFactoryDelegate) + EnumerableFactory.MakeGenericMethod(typeArgument) + .CreateDelegate(typeof(EnumerableFactoryDelegate)))(); } else { - return (ResolveDelegate)EnumerableMethod.MakeGenericMethod(typeArgument) - .CreateDelegate(typeof(ResolveDelegate)); + return (ResolveDelegate) + EnumerableMethod.MakeGenericMethod(typeArgument) + .CreateDelegate(typeof(ResolveDelegate)); } }; @@ -55,18 +52,16 @@ namespace Unity.Factories #region Implementation - private static object ResolveEnumerable(ref BuilderContext context) + private static object Resolver(ref BuilderContext context) { return ((UnityContainer)context.Container).ResolveEnumerable(context.Resolve, - context.Resolve, context.Name); } - private static object ResolveGeneric(ref BuilderContext context, Type type) + private static ResolveDelegate ResolverFactory() { - return ((UnityContainer)context.Container).ResolveEnumerable(context.Resolve, - context.Resolve, - type, context.Name); + Type type = typeof(TElement).GetGenericTypeDefinition(); + return (ref BuilderContext c) => ((UnityContainer)c.Container).ResolveEnumerable(c.Resolve, type, c.Name); } #endregion @@ -74,7 +69,7 @@ namespace Unity.Factories #region Nested Types - private delegate object ResolveEnumerableDelegate(ref BuilderContext context, Type type); + private delegate ResolveDelegate EnumerableFactoryDelegate(); #endregion } diff --git a/src/UnityContainer.Registration.cs b/src/UnityContainer.Registration.cs index e842c54b..75655c05 100644 --- a/src/UnityContainer.Registration.cs +++ b/src/UnityContainer.Registration.cs @@ -36,6 +36,7 @@ namespace Unity private readonly object _syncRoot = new object(); private LinkedNode _validators; + private Registrations _registrations; #endregion diff --git a/src/UnityContainer.Resolution.cs b/src/UnityContainer.Resolution.cs index 014de2e1..9401f51e 100644 --- a/src/UnityContainer.Resolution.cs +++ b/src/UnityContainer.Resolution.cs @@ -88,13 +88,12 @@ namespace Unity #region Resolving Enumerable - internal IEnumerable ResolveEnumerable(Func resolve, - Func resolveRegistration, + internal IEnumerable ResolveEnumerable(Func resolve, string name) { TElement value; - var set = new QuickSet(); - int hashCode = typeof(TElement).GetHashCode() & HashMask; + var set = new HashSet(); + int hash = typeof(TElement).GetHashCode() & HashMask; // Iterate over hierarchy for (var container = this; null != container; container = container._parent) @@ -104,20 +103,19 @@ namespace Unity // Hold on to registries var registry = container._registry; - var metadata = container._metadata; // Get indexes and iterate over them - var length = metadata.GetEntries(hashCode, out int[] data); + var length = container._metadata.GetEntries(hash, out int[] data); for (var i = 1; i < length; i++) { var index = data[i]; + var key = registry.Entries[index].Key.Name; - if (set.RequireToGrow) set = new QuickSet(set); - if (set.Add(registry.Entries[index].HashCode, registry.Entries[index].Key.Type)) + if (set.Add(key)) { try { - value = (TElement)resolveRegistration(typeof(TElement), registry.Entries[index].Key.Name, registry.Entries[index].Value); + value = (TElement)resolve(typeof(TElement), key, registry.Entries[index].Value); } catch (ArgumentException ex) when (ex.InnerException is TypeLoadException) { @@ -134,7 +132,8 @@ namespace Unity { try { - value = (TElement)resolve(typeof(TElement), name); + var registration = GetRegistration(typeof(TElement), name); + value = (TElement)resolve(typeof(TElement), name, registration); } catch { @@ -145,12 +144,11 @@ namespace Unity } } - internal IEnumerable ResolveEnumerable(Func resolve, - Func resolveRegistration, + internal IEnumerable ResolveEnumerable(Func resolve, Type typeDefinition, string name) { TElement value; - var set = new QuickSet(); + var set = new HashSet(); int hashCode = typeof(TElement).GetHashCode() & HashMask; int hashGeneric = typeDefinition.GetHashCode() & HashMask; @@ -162,21 +160,19 @@ namespace Unity // Hold on to registries var registry = container._registry; - var metadata = container._metadata; // Get indexes for bound types and iterate over them - var length = metadata.GetEntries(hashCode, out int[] data); + var length = container._metadata.GetEntries(hashCode, out int[] data); for (var i = 1; i < length; i++) { var index = data[i]; + var key = registry.Entries[index].Key.Name; - if (set.RequireToGrow) set = new QuickSet(set); - if (set.Add(registry.Entries[index].HashCode, registry.Entries[index].Key.Type)) + if (set.Add(key)) { - try { - value = (TElement)resolveRegistration(typeof(TElement), registry.Entries[index].Key.Name, registry.Entries[index].Value); + value = (TElement)resolve(typeof(TElement), key, registry.Entries[index].Value); } catch (ArgumentException ex) when (ex.InnerException is TypeLoadException) { @@ -188,17 +184,19 @@ namespace Unity } // Get indexes for unbound types and iterate over them - length = metadata.GetEntries(hashGeneric, typeDefinition, out data); + length = container._metadata.GetEntries(hashGeneric, typeDefinition, out data); for (var i = 1; i < length; i++) { var index = data[i]; + var key = registry.Entries[index].Key.Name; - if (set.RequireToGrow) set = new QuickSet(set); - if (set.Add(registry.Entries[index].HashCode, registry.Entries[index].Key.Type)) + if (set.Add(key)) { try { - value = (TElement)resolve(typeof(TElement), registry.Entries[index].Key.Name); + int hash = NamedType.GetHashCode(typeof(TElement), key) & 0x7FFFFFFF; + var registration = container.GetOrAdd(hash, typeof(TElement), key, registry.Entries[index].Value); + value = (TElement)resolve(typeof(TElement), key, registration); } catch (MakeGenericTypeFailedException) { continue; } catch (InvalidOperationException ex) when (ex.InnerException is InvalidRegistrationException) @@ -221,7 +219,8 @@ namespace Unity { try { - value = (TElement)resolve(typeof(TElement), name); + var registration = GetRegistration(typeof(TElement), name); + value = (TElement)resolve(typeof(TElement), name, registration); } catch { @@ -267,12 +266,11 @@ namespace Unity return argType; } - internal IEnumerable ResolveArray(Func resolve, - Func resolveRegistration) + internal IEnumerable ResolveArray(Func resolve, Type type) { TElement value; - var set = new QuickSet(); - int hashCode = typeof(TElement).GetHashCode() & HashMask; + var set = new HashSet(); + int hash = type.GetHashCode() & HashMask; // Iterate over hierarchy for (var container = this; null != container; container = container._parent) @@ -282,20 +280,19 @@ namespace Unity // Hold on to registries var registry = container._registry; - var metadata = container._metadata; // Get indexes and iterate over them - var length = metadata.GetEntries(hashCode, out int[] data); + var length = container._metadata.GetEntries(hash, type, out int[] data); for (var i = 1; i < length; i++) { var index = data[i]; - - if (set.RequireToGrow) set = new QuickSet(set); - if (set.Add(registry.Entries[index].HashCode, registry.Entries[index].Key.Type)) + var key = registry.Entries[index].Key.Name; + if (null == key) continue; + if (set.Add(key)) { try { - value = (TElement)resolveRegistration(typeof(TElement), registry.Entries[index].Key.Name, registry.Entries[index].Value); + value = (TElement)resolve(typeof(TElement), key, registry.Entries[index].Value); } catch (ArgumentException ex) when (ex.InnerException is TypeLoadException) { @@ -308,11 +305,13 @@ namespace Unity } } - internal IEnumerable GetArray(Func resolve) + internal IEnumerable ResolveArray(Func resolve, + Type type, Type typeDefinition) { TElement value; var set = new HashSet(); - int hashCode = typeof(TElement).GetHashCode() & HashMask; + int hashCode = type.GetHashCode() & HashMask; + int hashGeneric = typeDefinition.GetHashCode() & HashMask; // Iterate over hierarchy for (var container = this; null != container; container = container._parent) @@ -322,21 +321,92 @@ namespace Unity // Hold on to registries var registry = container._registry; - var metadata = container._metadata; - // Get indexes and iterate over them - var length = metadata.GetEntries(hashCode, out int[] data); + // Get indexes for bound types and iterate over them + var length = container._metadata.GetEntries(hashCode, type, out int[] data); for (var i = 1; i < length; i++) { var index = data[i]; - var name = registry.Entries[index].Key.Name; + var key = registry.Entries[index].Key.Name; - if (null == name) continue; - if (set.Add(name)) + if (null == key) continue; + if (set.Add(key)) { try { - value = (TElement)resolve(typeof(TElement), name, registry.Entries[index].Value); + value = (TElement)resolve(typeof(TElement), key, registry.Entries[index].Value); + } + catch (ArgumentException ex) when (ex.InnerException is TypeLoadException) + { + continue; + } + + yield return value; + } + } + + // Get indexes for unbound types and iterate over them + length = container._metadata.GetEntries(hashGeneric, typeDefinition, out data); + for (var i = 1; i < length; i++) + { + var index = data[i]; + var key = registry.Entries[index].Key.Name; + + if (null == key) continue; + if (set.Add(key)) + { + try + { + int hash = NamedType.GetHashCode(typeof(TElement), key) & 0x7FFFFFFF; + var registration = container.GetOrAdd(hash, typeof(TElement), key, registry.Entries[index].Value); + value = (TElement)resolve(typeof(TElement), key, registration); + } + catch (MakeGenericTypeFailedException) { continue; } + catch (InvalidOperationException ex) when (ex.InnerException is InvalidRegistrationException) + { + continue; + } + // TODO: Verify if required + //catch (ArgumentException ex) when (ex.InnerException is TypeLoadException) + //{ + // continue; + //} + + yield return value; + } + } + } + } + + internal IEnumerable ComplexArray(Func resolve, Type type) + { + TElement value; + var set = new HashSet(); + int hashCode = type.GetHashCode() & HashMask; + + // Iterate over hierarchy + for (var container = this; null != container; container = container._parent) + { + // Skip to parent if no data + if (null == container._metadata) continue; + + // Hold on to registries + var registry = container._registry; + + // Get indexes and iterate over them + var length = container._metadata.GetEntries(hashCode, type, out int[] data); + for (var i = 1; i < length; i++) + { + var index = data[i]; + var key = registry.Entries[index].Key.Name; + if (null == key) continue; + if (set.Add(key)) + { + try + { + int hash = NamedType.GetHashCode(typeof(TElement), key) & 0x7FFFFFFF; + var registration = container.GetOrAdd(hash, typeof(TElement), key, registry.Entries[index].Value); + value = (TElement)resolve(typeof(TElement), key, registration); } catch (ArgumentException ex) when (ex.InnerException is TypeLoadException) { @@ -349,11 +419,13 @@ namespace Unity } } - internal IEnumerable ResolveArrayTarget(Func resolve) + internal IEnumerable ComplexArray(Func resolve, + Type type, Type typeDefinition) { TElement value; var set = new HashSet(); - int hashCode = typeof(TTarget).GetHashCode() & HashMask; + int hashCode = type.GetHashCode() & HashMask; + int hashGeneric = typeDefinition.GetHashCode() & HashMask; // Iterate over hierarchy for (var container = this; null != container; container = container._parent) @@ -363,21 +435,22 @@ namespace Unity // Hold on to registries var registry = container._registry; - var metadata = container._metadata; - // Get indexes and iterate over them - var length = metadata.GetEntries(hashCode, out int[] data); + // Get indexes for bound types and iterate over them + var length = container._metadata.GetEntries(hashCode, type, out int[] data); for (var i = 1; i < length; i++) { var index = data[i]; - var name = registry.Entries[index].Key.Name; + var key = registry.Entries[index].Key.Name; - if (null == name) continue; - if (set.Add(name)) + if (null == key) continue; + if (set.Add(key)) { try { - value = (TElement)resolve(typeof(TElement), name); + int hash = NamedType.GetHashCode(typeof(TElement), key) & 0x7FFFFFFF; + var registration = container.GetOrAdd(hash, typeof(TElement), key, registry.Entries[index].Value); + value = (TElement)resolve(typeof(TElement), key, registration); } catch (ArgumentException ex) when (ex.InnerException is TypeLoadException) { @@ -387,43 +460,33 @@ namespace Unity yield return value; } } - } - } - internal IEnumerable DefinitionArray(Func resolve, Type type) - { - TElement value; - var set = new HashSet(); - int hashCode = typeof(TElement).GetHashCode() & HashMask; - - // Iterate over hierarchy - for (var container = this; null != container; container = container._parent) - { - // Skip to parent if no data - if (null == container._metadata) continue; - - // Hold on to registries - var registry = container._registry; - var metadata = container._metadata; - - // Get indexes and iterate over them - var length = metadata.GetEntries(hashCode, out int[] data); + // Get indexes for unbound types and iterate over them + length = container._metadata.GetEntries(hashGeneric, typeDefinition, out data); for (var i = 1; i < length; i++) { var index = data[i]; - var name = registry.Entries[index].Key.Name; + var key = registry.Entries[index].Key.Name; - if (null == name) continue; - if (set.Add(name)) + if (null == key) continue; + if (set.Add(key)) { try { - value = (TElement)resolve(typeof(TElement), name, registry.Entries[index].Value); + int hash = NamedType.GetHashCode(typeof(TElement), key) & 0x7FFFFFFF; + var registration = container.GetOrAdd(hash, typeof(TElement), key, registry.Entries[index].Value); + value = (TElement)resolve(typeof(TElement), key, registration); } - catch (ArgumentException ex) when (ex.InnerException is TypeLoadException) + catch (MakeGenericTypeFailedException) { continue; } + catch (InvalidOperationException ex) when (ex.InnerException is InvalidRegistrationException) { continue; } + // TODO: Verify if required + //catch (ArgumentException ex) when (ex.InnerException is TypeLoadException) + //{ + // continue; + //} yield return value; }