diff --git a/src/Pipeline/Builder/Lifetime/Default.cs b/src/Pipeline/Builder/Lifetime/Default.cs deleted file mode 100644 index da614f73..00000000 --- a/src/Pipeline/Builder/Lifetime/Default.cs +++ /dev/null @@ -1,148 +0,0 @@ -using System; -using System.Diagnostics; -using System.Threading.Tasks; -using Unity.Builder; -using Unity.Lifetime; -using Unity.Storage; - -namespace Unity -{ - public ref partial struct PipelineBuilder - { - private BuildPipelineAsync DefaultLifetimeAsync() - { - var type = Type; - var name = Name; - var manager = Registration?.LifetimeManager; - var registration = Registration; - var synchronized = manager as SynchronizedLifetimeManager; - var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error)); - Debug.Assert(null != manager); - - return (ref PipelineContext context) => - { - var lifetime = context.ContainerContext.Lifetime; - var unity = context.ContainerContext; - var overrides = context.Overrides; - - // In Sync mode just execute pipeline - if (!context.RunAsync) - { - var value = manager.GetValue(lifetime); - if (LifetimeManager.NoValue != value) - return new ValueTask(value); - - var c = new BuilderContext - { - List = new PolicyList(), - IsAsync = true, - Type = type, - ContainerContext = unity, - Registration = registration, - Overrides = overrides, - DeclaringType = type, - }; - - try - { - // Compose down the chain - value = pipeline(ref c); - manager.SetValue(value, lifetime); - return new ValueTask(value); - } - catch (Exception ex)// when (null != synchronized) - { -#if NET40 || NET45 || NETSTANDARD1_0 - var taskSource = new TaskCompletionSource(); - taskSource.SetException(ex); - var ext = taskSource.Task; -#else - var ext = Task.FromException(ex); -#endif - synchronized?.Recover(); - return new ValueTask(ext); - } - } - - // Async mode - - // Create and return a task that creates an object - var task = Task.Factory.StartNew(() => - { - var value = manager.GetValue(lifetime); - if (LifetimeManager.NoValue != value) return value; - - var c = new BuilderContext - { - List = new PolicyList(), - IsAsync = true, - Type = type, - ContainerContext = unity, - Registration = registration, - Overrides = overrides, - DeclaringType = type, - }; - - // Execute pipeline - try - { - value = pipeline(ref c); - manager.SetValue(value, lifetime); - return value; - } - catch when (null != synchronized) - { - synchronized.Recover(); - throw; - } - }); - return new ValueTask(task); - }; - } - - - private PipelineDelegate DefaultLifetime() - { - var type = Type; - var name = Name; - var manager = Registration?.LifetimeManager; - var registration = Registration; - var synchronized = manager as SynchronizedLifetimeManager; - var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error)); - Debug.Assert(null != manager); - - return (ref BuilderContext context) => - { - var lifetime = context.ContainerContext.Lifetime; - - var value = manager.GetValue(lifetime); - if (LifetimeManager.NoValue != value) - return new ValueTask(value); - - // Set Policy storage if required - if (null == context.List) - context.List = new PolicyList(); - - try - { - // Compose down the chain - value = pipeline(ref context); - manager.SetValue(value, lifetime); - return new ValueTask(value); - } - catch (Exception ex)// when (null != synchronized) - { -#if NET40 || NET45 || NETSTANDARD1_0 - var taskSource = new TaskCompletionSource(); - taskSource.SetException(ex); - var ext = taskSource.Task; -#else - var ext = Task.FromException(ex); -#endif - synchronized?.Recover(); - return new ValueTask(ext); - } - }; - } - } -} diff --git a/src/Pipeline/Builder/Lifetime/PerResolve.cs b/src/Pipeline/Builder/Lifetime/PerResolve.cs deleted file mode 100644 index a8eaa4d7..00000000 --- a/src/Pipeline/Builder/Lifetime/PerResolve.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Threading.Tasks; -using Unity.Builder; -using Unity.Lifetime; -using Unity.Storage; - -namespace Unity -{ - public ref partial struct PipelineBuilder - { - private BuildPipelineAsync PerResolveLifetimeAsync() - { - var type = Type; - var name = Name; - var registration = Registration; - var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error)); - - return (ref PipelineContext context) => - { - object value; - var lifetime = context.ContainerContext.Lifetime; - var unity = context.ContainerContext; - var overrides = context.Overrides; - - // In Sync mode just execute pipeline - if (!context.RunAsync) - { - var c = new BuilderContext - { - List = new PolicyList(), - IsAsync = true, - Type = type, - ContainerContext = unity, - Registration = registration, - Overrides = overrides, - DeclaringType = type, - }; - - // Compose down the chain - value = pipeline(ref c); - return new ValueTask(value); - } - - // Async mode - - // Create and return a task that creates an object - var task = Task.Factory.StartNew(() => - { - var c = new BuilderContext - { - List = new PolicyList(), - IsAsync = true, - Type = type, - ContainerContext = unity, - Registration = registration, - Overrides = overrides, - DeclaringType = type, - }; - - // Execute pipeline - return pipeline(ref c); - }); - - return new ValueTask(task); - }; - } - - - private PipelineDelegate PerResolveLifetime() - { - var type = Type; - var name = Name; - var registration = Registration; - var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error)); - - return (ref BuilderContext context) => - { - object value; - var lifetime = context.ContainerContext.Lifetime; - - // Get it from context - var manager = (LifetimeManager?)context.Get(typeof(LifetimeManager)); - - // Return if holds value - if (null != manager) - { - value = manager.GetValue(lifetime); - if (LifetimeManager.NoValue != value) - { - return new ValueTask(value); - } - } - - // Set Policy storage if required - if (null == context.List) - context.List = new PolicyList(); - - // Compose down the chain - value = pipeline(ref context); - return new ValueTask(value); - }; - } - } -} diff --git a/src/Pipeline/Builder/Lifetime/PerThread.cs b/src/Pipeline/Builder/Lifetime/PerThread.cs deleted file mode 100644 index 302b9262..00000000 --- a/src/Pipeline/Builder/Lifetime/PerThread.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System; -using System.Diagnostics; -using System.Threading.Tasks; -using Unity.Builder; -using Unity.Exceptions; -using Unity.Lifetime; -using Unity.Storage; - -namespace Unity -{ - public ref partial struct PipelineBuilder - { - private BuildPipelineAsync PerThreadLifetimeAsync() - { - var type = Type; - var name = Name; - var registration = Registration; - var manager = Registration?.LifetimeManager; - var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error)); - - - return (ref PipelineContext context) => - { - // Verify is not async - if (context.RunAsync || context.RunningAsync) - { - var ex = new InvalidRegistrationException("Lifetime:PerThread is not designed to participate in async operations"); -#if NET40 || NET45 || NETSTANDARD1_0 - var taskSource = new TaskCompletionSource(); - taskSource.SetException(ex); - var ext = taskSource.Task; -#else - var ext = Task.FromException(ex); -#endif - return new ValueTask(ext); - } - - Debug.Assert(null != manager); - - // Compose - try - { - var unity = context.ContainerContext; - var overrides = context.Overrides; - var lifetime = context.ContainerContext.Lifetime; - var value = manager.GetValue(lifetime); - - if (LifetimeManager.NoValue != value) - return new ValueTask(value); - - var c = new BuilderContext - { - List = new PolicyList(), - IsAsync = true, - Type = type, - ContainerContext = unity, - Registration = registration, - Overrides = overrides, - DeclaringType = type, - Parent = IntPtr.Zero, - }; - - // Compose down the chain - value = pipeline(ref c); - manager.SetValue(value, lifetime); - return new ValueTask(value); - } - catch (Exception ex)// when (null != synchronized) - { -#if NET40 || NET45 || NETSTANDARD1_0 - var taskSource = new TaskCompletionSource(); - taskSource.SetException(ex); - var ext = taskSource.Task; -#else - var ext = Task.FromException(ex); -#endif - return new ValueTask(ext); - } - }; - } - - - private PipelineDelegate PerThreadLifetime() - { - var type = Type; - var name = Name; - var registration = Registration; - var manager = Registration?.LifetimeManager; - var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error)); - - return (ref BuilderContext context) => - { - // Verify is not async - if (context.IsAsync) - { - var ex = new InvalidRegistrationException("Lifetime:PerThread is not designed to participate in async operations"); -#if NET40 || NET45 || NETSTANDARD1_0 - var taskSource = new TaskCompletionSource(); - taskSource.SetException(ex); - var ext = taskSource.Task; -#else - var ext = Task.FromException(ex); -#endif - return new ValueTask(ext); - } - - Debug.Assert(null != manager); - - // Compose - try - { - var lifetime = context.ContainerContext.Lifetime; - var value = manager.GetValue(lifetime); - - if (LifetimeManager.NoValue != value) - return new ValueTask(value); - - // Set Policy storage if required - if (null == context.List) - context.List = new PolicyList(); - - // Compose down the chain - value = pipeline(ref context); - manager.SetValue(value, lifetime); - return new ValueTask(value); - } - catch (Exception ex)// when (null != synchronized) - { -#if NET40 || NET45 || NETSTANDARD1_0 - var taskSource = new TaskCompletionSource(); - taskSource.SetException(ex); - var ext = taskSource.Task; -#else - var ext = Task.FromException(ex); -#endif - return new ValueTask(ext); - } - }; - } - } -} diff --git a/src/Pipeline/Builder/Lifetime/Transient.cs b/src/Pipeline/Builder/Lifetime/Transient.cs deleted file mode 100644 index 55468a89..00000000 --- a/src/Pipeline/Builder/Lifetime/Transient.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.Threading.Tasks; -using Unity.Builder; -using Unity.Storage; - -namespace Unity -{ - public ref partial struct PipelineBuilder - { - private BuildPipelineAsync TransientLifetimeAsync() - { - var type = Type; - var name = Name; - var registration = Registration; - var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error)); - - return (ref PipelineContext context) => - { - // Async mode - var unity = context.ContainerContext; - var overrides = context.Overrides; - - //In Sync mode just execute pipeline - if (!context.RunAsync) - { - var c = new BuilderContext - { - List = new PolicyList(), - IsAsync = true, - Type = type, - ContainerContext = unity, - Registration = registration, - Overrides = overrides, - DeclaringType = type, - Parent = IntPtr.Zero, - }; - - // Execute pipeline - var value = pipeline(ref c); - return new ValueTask(value); - } - - // Create and return a task that creates an object - var task = Task.Factory.StartNew(() => - { - var c = new BuilderContext - { - List = new PolicyList(), - IsAsync = true, - Type = type, - ContainerContext = unity, - Registration = registration, - Overrides = overrides, - DeclaringType = type, - Parent = IntPtr.Zero, - }; - - // Execute pipeline - return pipeline(ref c); - }); - - return new ValueTask(task); - }; - } - - private PipelineDelegate TransientLifetime() - { - var type = Type; - var name = Name; - var registration = Registration; - var pipeline = Pipeline() ?? ((ref BuilderContext c) => throw new ResolutionFailedException(type, name, error)); - - return (ref BuilderContext context) => - { - // Set Policy storage if required - if (null == context.List) - context.List = new PolicyList(); - - var value = pipeline(ref context); - return new ValueTask(value); - }; - } - } -} diff --git a/src/Pipeline/Builder/PipelineBuilder.cs b/src/Pipeline/Builder/PipelineBuilder.cs index c5075725..456cbce3 100644 --- a/src/Pipeline/Builder/PipelineBuilder.cs +++ b/src/Pipeline/Builder/PipelineBuilder.cs @@ -4,7 +4,9 @@ using System.Diagnostics; using System.Linq; using System.Security; using Unity.Builder; +using Unity.Injection; using Unity.Lifetime; +using Unity.Policy; using Unity.Registration; using Unity.Resolution; using static Unity.UnityContainer; @@ -32,33 +34,48 @@ namespace Unity { Type = registration.Type ?? typeof(object); Name = registration.Name; + BuildType = registration.BuildType; + BuildRequired = registration.BuildRequired; + LifetimeManager = registration.LifetimeManager; + InjectionMembers = registration.InjectionMembers; + Registration = registration; ContainerContext = container.Context; - Seed = Registration.Pipeline; + Seed = registration.Pipeline; _enumerator = pipelines.GetEnumerator(); Debug.Assert(null != _enumerator); } public PipelineBuilder(Type type, string? name, UnityContainer container, IEnumerable pipelines) { - Seed = null; Type = type; Name = name; + BuildType = null; + BuildRequired = false; + LifetimeManager = null; + InjectionMembers = null; + Registration = null; ContainerContext = container.Context; + Seed = null; _enumerator = pipelines.GetEnumerator(); } public PipelineBuilder(Type type, string? name, UnityContainer container, IRegistration registration) { - Seed = registration?.Pipeline; Type = type; Name = name; + BuildType = registration.BuildType; + BuildRequired = registration.BuildRequired; + LifetimeManager = registration.LifetimeManager; + InjectionMembers = registration.InjectionMembers; + Registration = registration; ContainerContext = container.Context; + Seed = registration.Pipeline; _enumerator = (registration?.Processors ?? Enumerable.Empty()).GetEnumerator(); } @@ -67,10 +84,15 @@ namespace Unity { Type = context.Type; Name = context.Name; + BuildType = context.Registration?.BuildType; + BuildRequired = context.Registration?.BuildRequired ?? false; + LifetimeManager = context.Registration?.LifetimeManager; + InjectionMembers = context.Registration?.InjectionMembers; + Registration = context.Registration; ContainerContext = context.ContainerContext; - Seed = Registration?.Pipeline; + Seed = context.Registration?.Pipeline; _enumerator = (context.Registration?.Processors ?? Enumerable.Empty()).GetEnumerator(); } @@ -84,11 +106,21 @@ namespace Unity public string? Name { get; } + public LifetimeManager? LifetimeManager { get; } + + public InjectionMember[]? InjectionMembers { get; set; } + + public bool BuildRequired { get; } + + public Converter? BuildType { get; } + + + public ResolveDelegate? Seed { get; private set; } public readonly ContainerContext ContainerContext; - public readonly IRegistration? Registration; + public IRegistration? Registration { get; } #endregion @@ -113,35 +145,6 @@ namespace Unity : Seed; } - public PipelineDelegate PipelineDelegate() - { - var manager = Registration?.LifetimeManager; - - return manager switch - { - null => TransientLifetime(), - TransientLifetimeManager _ => TransientLifetime(), - PerResolveLifetimeManager _ => PerResolveLifetime(), - PerThreadLifetimeManager _ => PerThreadLifetime(), - _ => DefaultLifetime() - }; - } - - public BuildPipelineAsync BuildPipelineAsync() - { - var manager = Registration?.LifetimeManager; - - return manager switch - { - null => TransientLifetimeAsync(), - TransientLifetimeManager _ => TransientLifetimeAsync(), - PerResolveLifetimeManager _ => PerResolveLifetimeAsync(), - PerThreadLifetimeManager _ => PerThreadLifetimeAsync(), - _ => DefaultLifetimeAsync() - }; - } - - #endregion } } diff --git a/src/Pipeline/Factory/FactoryPipeline.cs b/src/Pipeline/Factory/FactoryPipeline.cs index 19b7b9ae..d86b4a07 100644 --- a/src/Pipeline/Factory/FactoryPipeline.cs +++ b/src/Pipeline/Factory/FactoryPipeline.cs @@ -29,8 +29,7 @@ namespace Unity // Try to get resolver Type? generic = null; - var resolver = builder.Registration?.Pipeline ?? - builder.Registration?.Get(typeof(ResolveDelegate)) ?? + var resolver = builder.Registration?.Get(typeof(ResolveDelegate)) ?? builder.ContainerContext.Get(builder.Type, typeof(ResolveDelegate)); if (null == resolver) @@ -68,7 +67,7 @@ namespace Unity { if (builder.Type.GetArrayRank() == 1) { - var resolve = ArrayResolver.Factory(builder.Type, builder.Registration); + var resolve = ArrayResolver.Factory(builder.Type, (IRegistration)builder.Registration); return builder.Pipeline((ref BuilderContext context) => resolve(ref context)); } else @@ -104,7 +103,7 @@ namespace Unity Debug.Assert(null != builder.Type); return null != factory - ? builder.Pipeline(factory(builder.Type, builder.Registration)) + ? builder.Pipeline(factory(builder.Type, (IRegistration)builder.Registration)) : builder.Pipeline(); } diff --git a/src/Pipeline/Mapping/MappingDiagnostic.cs b/src/Pipeline/Mapping/MappingDiagnostic.cs index 75626f8c..75ace8b5 100644 --- a/src/Pipeline/Mapping/MappingDiagnostic.cs +++ b/src/Pipeline/Mapping/MappingDiagnostic.cs @@ -24,12 +24,12 @@ namespace Unity else { // Implicit Registration - if (null != builder.Registration.BuildType) - builder.Type = builder.Registration.BuildType(builder.Type); + if (null != builder.BuildType) + builder.Type = builder.BuildType(builder.Type); } // If nothing to map or build required, just create it - if (builder.Registration.BuildRequired || requestedType == builder.Type) + if (builder.BuildRequired || requestedType == builder.Type) return builder.Pipeline(); var type = builder.Type; diff --git a/src/Pipeline/Mapping/MappingPipeline.cs b/src/Pipeline/Mapping/MappingPipeline.cs index 3f49cbe0..42654495 100644 --- a/src/Pipeline/Mapping/MappingPipeline.cs +++ b/src/Pipeline/Mapping/MappingPipeline.cs @@ -29,7 +29,7 @@ namespace Unity } // If nothing to map or build required, just create it - if ((builder.Registration?.BuildRequired ?? false) || requestedType == builder.Type) + if ((builder.BuildRequired) || requestedType == builder.Type) return builder.Pipeline(); var type = builder.Type; diff --git a/src/UnityContainer.IUnityContainer.cs b/src/UnityContainer.IUnityContainer.cs index 875c6531..2e4a1aa7 100644 --- a/src/UnityContainer.IUnityContainer.cs +++ b/src/UnityContainer.IUnityContainer.cs @@ -202,35 +202,38 @@ namespace Unity #region Getting objects + /* /// [SecuritySafeCritical] object? IUnityContainer.Resolve(Type type, string? name, params ResolverOverride[] overrides) { - var registration = GetRegistration(type ?? throw new ArgumentNullException(nameof(type)), name); + var key = new HashKey(type ?? throw new ArgumentNullException(nameof(type)), name); + var pipeline = GetPipeline(ref key); - // Check if already got value - if (null != registration.LifetimeManager) + // Check if already created and acquire a lock if not + var manager = pipeline.Target as LifetimeManager; + if (null != manager) { - var value = registration.LifetimeManager.Get(LifetimeContainer); + // Make blocking check for result + var value = manager.Get(LifetimeContainer); if (LifetimeManager.NoValue != value) return value; } // Setup Context - var synchronized = registration.LifetimeManager as SynchronizedLifetimeManager; + var synchronized = manager as SynchronizedLifetimeManager; var context = new BuilderContext { List = new PolicyList(), Type = type, Overrides = overrides, - Registration = registration, ContainerContext = Context, }; // Execute pipeline try { - var value = context.Pipeline(ref context); - registration.LifetimeManager?.Set(value, LifetimeContainer); + var value = pipeline(ref context); + manager?.Set(value, LifetimeContainer); return value; } catch (Exception ex) @@ -247,6 +250,7 @@ namespace Unity else throw; } } + */ #endregion @@ -294,5 +298,51 @@ namespace Unity IUnityContainer? IUnityContainer.Parent => _parent; #endregion + + /// + [SecuritySafeCritical] + object? IUnityContainer.Resolve(Type type, string? name, params ResolverOverride[] overrides) + { + var registration = GetRegistration(type ?? throw new ArgumentNullException(nameof(type)), name); + + // Check if already got value + if (null != registration.LifetimeManager) + { + var value = registration.LifetimeManager.Get(LifetimeContainer); + if (LifetimeManager.NoValue != value) return value; + } + + // Setup Context + var synchronized = registration.LifetimeManager as SynchronizedLifetimeManager; + var context = new BuilderContext + { + List = new PolicyList(), + Type = type, + Overrides = overrides, + Registration = registration, + ContainerContext = Context, + }; + + // Execute pipeline + try + { + var value = context.Pipeline(ref context); + registration.LifetimeManager?.Set(value, LifetimeContainer); + return value; + } + catch (Exception ex) + { + synchronized?.Recover(); + + if (ex is InvalidRegistrationException || + ex is CircularDependencyException || + ex is ObjectDisposedException) + { + var message = CreateErrorMessage(ex); + throw new ResolutionFailedException(context.Type, context.Name, message, ex); + } + else throw; + } + } } } diff --git a/src/UnityContainer.IUnityContainerAsync.cs b/src/UnityContainer.IUnityContainerAsync.cs index 56c1d024..531658ae 100644 --- a/src/UnityContainer.IUnityContainerAsync.cs +++ b/src/UnityContainer.IUnityContainerAsync.cs @@ -188,6 +188,9 @@ namespace Unity #region Resolution + + + /* /// [SecuritySafeCritical] ValueTask IUnityContainerAsync.ResolveAsync(Type type, string? name, params ResolverOverride[] overrides) @@ -248,9 +251,7 @@ namespace Unity } })); } - - - /* + */ /// [SecuritySafeCritical] ValueTask IUnityContainerAsync.ResolveAsync(Type type, string? name, params ResolverOverride[] overrides) @@ -300,14 +301,13 @@ namespace Unity ex is CircularDependencyException || ex is ObjectDisposedException) { - var message = CreateMessage(ex); + var message = CreateErrorMessage(ex); throw new ResolutionFailedException(context.Type, context.Name, message, ex); } else throw; } })); } - */ public ValueTask> Resolve(Type type, Regex regex, params ResolverOverride[] overrides) { diff --git a/src/UnityContainer.Pipeline.cs b/src/UnityContainer.Pipeline.cs index 7285aa16..2b8194cb 100644 --- a/src/UnityContainer.Pipeline.cs +++ b/src/UnityContainer.Pipeline.cs @@ -88,83 +88,86 @@ namespace Unity #if NETSTANDARD1_0 || NETCOREAPP1_0 private ResolveDelegate GenericGetPipeline(ref HashKey key, TypeInfo info) -#else - private ResolveDelegate GenericGetPipeline(ref HashKey keyExact) -#endif { - throw new NotImplementedException(); + Debug.Assert(null != info); +#else + private ResolveDelegate GenericGetPipeline(ref HashKey key) + { +#endif + Debug.Assert(null != key.Type); - // bool initGenerics = true; - // Type? generic = null; - // int targetBucket; - // var keyGeneric = new HashKey(); - // var keyDefault = new HashKey(); + int targetBucket; + bool initGenerics = true; + var keyGeneric = new HashKey(); + var keyDefault = new HashKey(); + Type type = key.Type; + Type? generic = null; + var name = key.Name; - // // Iterate through containers hierarchy - // for (UnityContainer? container = this; null != container; container = container._parent) - // { - // // Skip to parent if no registrations - // if (null == container._metadata) continue; + // Iterate through containers hierarchy + for (UnityContainer? container = this; null != container; container = container._parent) + { + // Skip to parent if no registrations + if (null == container._metadata) continue; - // Debug.Assert(null != container._registry); - // var registry = container._registry; + Debug.Assert(null != container._registry); + var registry = container._registry; - // // Check for exact match - // targetBucket = keyExact.HashCode % registry.Buckets.Length; - // for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next) - // { - // ref var candidate = ref registry.Entries[i]; - // if (candidate.Key != keyExact) continue; + // Check for exact match + targetBucket = key.HashCode % registry.Buckets.Length; + for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next) + { + ref var candidate = ref registry.Entries[i]; + if (candidate.Key != key) continue; - // // Found a registration - // if (!(candidate.Policies is IRegistration)) - // candidate.Policies = container.CreateRegistration(type, name, candidate.Policies); + Debug.Assert(null != candidate.Pipeline); + + // Found a registration + return candidate.Pipeline; + } - // return ((IRegistration)candidate.Policies).Pipeline; - // } + // Generic registrations + if (initGenerics) + { + initGenerics = false; - // // Generic registrations - // if (initGenerics) - // { - // initGenerics = false; +#if NETSTANDARD1_0 || NETCOREAPP1_0 + generic = info.GetGenericTypeDefinition(); +#else + generic = type.GetGenericTypeDefinition(); +#endif + keyGeneric = new HashKey(generic, name); + keyDefault = new HashKey(generic); + } - //#if NETSTANDARD1_0 || NETCOREAPP1_0 - // generic = info.GetGenericTypeDefinition(); - //#else - // generic = type.GetGenericTypeDefinition(); - //#endif - // keyGeneric = new HashKey(generic, name); - // keyDefault = new HashKey(generic); - // } + // Check for factory with same name + targetBucket = keyGeneric.HashCode % registry.Buckets.Length; + for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next) + { + ref var candidate = ref registry.Entries[i]; + if (candidate.Key != keyGeneric) + continue; - // // Check for factory with same name - // targetBucket = keyGeneric.HashCode % registry.Buckets.Length; - // for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next) - // { - // ref var candidate = ref registry.Entries[i]; - // if (candidate.Key != keyGeneric) - // continue; + // Found a factory + return container.PipelineFromFactory(ref key, (IRegistration)candidate.Policies); + } - // // Found a factory - // return null; - // } + // Check for default factory + targetBucket = keyDefault.HashCode % registry.Buckets.Length; + for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next) + { + ref var candidate = ref registry.Entries[i]; + if (candidate.Key != keyDefault) + continue; - // // Check for default factory - // targetBucket = keyDefault.HashCode % registry.Buckets.Length; - // for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next) - // { - // ref var candidate = ref registry.Entries[i]; - // if (candidate.Key != keyDefault) - // continue; + // Found a factory + return container.PipelineFromFactory(ref key, (IRegistration)candidate.Policies); + } + } - // // Found a factory - // return null; - // } - // } + Debug.Assert(null != _root); - // Debug.Assert(null != _root); - - // return null; + return _root.PipelineFromType(ref key); } #endregion @@ -174,6 +177,7 @@ namespace Unity private ResolveDelegate PipelineFromType(ref HashKey key) { + Debug.Assert(null != key.Type); Debug.Assert(null != _registry); var type = key.Type; @@ -307,6 +311,100 @@ namespace Unity }; } + private ResolveDelegate PipelineFromFactory(ref HashKey key, IRegistration registration) + { + Debug.Assert(null != _registry); + Debug.Assert(null != key.Type); + + var type = key.Type; + var name = key.Name; + int count = -1; + int position = 0; + var collisions = 0; + ResolveDelegate? pipeline = null; + + // Add Pipeline to the Registry + lock (_syncLock) + { + var targetBucket = key.HashCode % _registry.Buckets.Length; + for (var i = _registry.Buckets[targetBucket]; i >= 0; i = _registry.Entries[i].Next) + { + ref var candidate = ref _registry.Entries[i]; + if (candidate.Key != key) + { + collisions++; + continue; + } + + Debug.Assert(null != candidate.Pipeline); + + // Has already been created + return candidate.Pipeline; + } + + // Expand if required + if (_registry.RequireToGrow || CollisionsCutPoint < collisions) + { + _registry = new Registry(_registry); + targetBucket = key.HashCode % _registry.Buckets.Length; + } + + // Create new entry + ref var entry = ref _registry.Entries[_registry.Count]; + entry.Key = key; + entry.Type = type; + entry.Pipeline = BuildPipeline; + entry.Next = _registry.Buckets[targetBucket]; + position = _registry.Count++; + _registry.Buckets[targetBucket] = position; + } + + // Return temporary pipeline + return BuildPipeline; + + + // Create pipeline and add to Registry + object? BuildPipeline(ref BuilderContext context) + { + // Wait for right moment + while (0 != Interlocked.Increment(ref count)) + { + Interlocked.Decrement(ref count); +#if NETSTANDARD1_0 || NETCOREAPP1_0 + for (var i = 0; i < 100; i++) ; +#else + Thread.SpinWait(100); +#endif + } + + try + { + // Create if required + if (null == pipeline) + { + //BuildType = factory.BuildType; + //Next = factory.Next; + //LifetimeManager = factory.LifetimeManager?.CreateLifetimePolicy(); + //Pipeline = factory.Pipeline; + //InjectionMembers = factory.InjectionMembers; + //BuildRequired = null != InjectionMembers && InjectionMembers.Any(m => m.BuildRequired); + + + PipelineBuilder builder = new PipelineBuilder(type, name, this, Context.TypePipelineCache); + pipeline = builder.Pipeline(); + + Debug.Assert(null != pipeline); + } + + return pipeline(ref context); + } + finally + { + Interlocked.Decrement(ref count); + } + }; + } + #endregion } } diff --git a/src/UnityContainer.Registration.cs b/src/UnityContainer.Registration.cs index 05cab545..2d1bd4a4 100644 --- a/src/UnityContainer.Registration.cs +++ b/src/UnityContainer.Registration.cs @@ -2,11 +2,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Reflection; -using Unity.Builder; using Unity.Lifetime; using Unity.Policy; using Unity.Registration; -using Unity.Resolution; using Unity.Storage; namespace Unity