This commit is contained in:
Eugene Sadovoi 2019-06-07 21:09:40 -04:00
Родитель 55e5eff24f
Коммит d48e431cb6
9 изменённых файлов: 178 добавлений и 327 удалений

Просмотреть файл

@ -22,7 +22,7 @@ namespace Unity.Registration
Converter<Type, Type>? BuildType { get; }
LifetimeManager? LifetimeManager { get; }
LifetimeManager LifetimeManager { get; }
UnityContainer Owner { get; }
}

Просмотреть файл

@ -19,17 +19,15 @@ namespace Unity.Registration
{
Next = null;
Type = type;
LifetimeManager = new TransientLifetimeManager();
InjectionMembers = null;
BuildRequired = false;
}
public ExplicitRegistration(UnityContainer owner, string? name, Type? type, LifetimeManager lifetimeManager)
: base(owner, name)
: base(owner, name, lifetimeManager)
{
Next = null;
Type = type;
LifetimeManager = lifetimeManager;
InjectionMembers = null;
BuildRequired = null != InjectionMembers && InjectionMembers.Any(m => m.BuildRequired);
@ -38,10 +36,9 @@ namespace Unity.Registration
}
public ExplicitRegistration(UnityContainer owner, string? name, Type? type, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
: base(owner, name)
: base(owner, name, lifetimeManager)
{
Type = type;
LifetimeManager = lifetimeManager;
Next = owner.Defaults;
InjectionMembers = null != injectionMembers && 0 < injectionMembers.Length ? injectionMembers : null;
BuildRequired = null != InjectionMembers && InjectionMembers.Any(m => m.BuildRequired) || lifetimeManager is PerResolveLifetimeManager;

Просмотреть файл

@ -12,7 +12,7 @@ using Unity.Storage;
namespace Unity.Registration
{
[DebuggerDisplay("Registration.Implicit({Count})")]
//[DebuggerDisplay("Registration.Implicit({Count})")]
//[DebuggerTypeProxy(typeof(ImplicitRegistrationDebugProxy))]
public class ImplicitRegistration : PolicySet, IRegistration
{
@ -26,17 +26,19 @@ namespace Unity.Registration
#region Constructors
public ImplicitRegistration(UnityContainer owner, string? name)
public ImplicitRegistration(UnityContainer owner, string? name, LifetimeManager? manager = null)
: base(owner)
{
Name = name;
LifetimeManager = manager ?? new TransientLifetimeManager();
}
public ImplicitRegistration(UnityContainer owner, string? name, IPolicySet? set)
public ImplicitRegistration(UnityContainer owner, string? name, LifetimeManager manager, IPolicySet? set)
: base(owner)
{
Name = name;
Next = (PolicyEntry?)set;
LifetimeManager = manager;
}
public ImplicitRegistration(UnityContainer owner, string? name, ImplicitRegistration factory)
@ -45,17 +47,18 @@ namespace Unity.Registration
Name = name;
BuildType = factory.BuildType;
Next = factory.Next;
LifetimeManager = factory.LifetimeManager?.CreateLifetimePolicy();
LifetimeManager = factory.LifetimeManager?.CreateLifetimePolicy() ?? new TransientLifetimeManager();
Pipeline = factory.Pipeline;
InjectionMembers = factory.InjectionMembers;
BuildRequired = null != InjectionMembers && InjectionMembers.Any(m => m.BuildRequired);
}
public ImplicitRegistration(UnityContainer owner, string? name, ResolveDelegate<BuilderContext> pipeline)
public ImplicitRegistration(UnityContainer owner, string? name, LifetimeManager manager, ResolveDelegate<BuilderContext> pipeline)
: base(owner)
{
Name = name;
Pipeline = pipeline;
LifetimeManager = manager;
}
#endregion
@ -75,7 +78,7 @@ namespace Unity.Registration
public virtual Converter<Type, Type>? BuildType { get; }
public LifetimeManager? LifetimeManager { get; protected set; }
public LifetimeManager LifetimeManager { get; protected set; }
public virtual void Add(IPolicySet set)
{

Просмотреть файл

@ -191,7 +191,6 @@ namespace Unity
/*
/// <inheritdoc />
[SecuritySafeCritical]
ValueTask<object?> IUnityContainerAsync.ResolveAsync(Type type, string? name, params ResolverOverride[] overrides)
@ -252,64 +251,6 @@ namespace Unity
}
}));
}
*/
/// <inheritdoc />
[SecuritySafeCritical]
ValueTask<object?> IUnityContainerAsync.ResolveAsync(Type type, string? name, params ResolverOverride[] overrides)
{
var registration = GetRegistration(type ?? throw new ArgumentNullException(nameof(type)), name);
if (null != registration.LifetimeManager)
{
// Make unblocking check if already has result
var value = registration.LifetimeManager.TryGet(LifetimeContainer);
if (LifetimeManager.NoValue != value) return new ValueTask<object?>(value);
}
return new ValueTask<object?>(Task.Factory.StartNew<object?>(delegate
{
// Check if already created and acquire a lock
if (null != registration.LifetimeManager)
{
var value = registration.LifetimeManager.Get(LifetimeContainer);
if (LifetimeManager.NoValue != value) return new ValueTask<object?>(value);
}
// Setup Context
var synchronized = registration.LifetimeManager as SynchronizedLifetimeManager;
var context = new BuilderContext
{
List = new PolicyList(),
Type = type,
Name = name,
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;
}
}));
}
public ValueTask<IEnumerable<object>> Resolve(Type type, Regex regex, params ResolverOverride[] overrides)
{

Просмотреть файл

@ -20,25 +20,9 @@ namespace Unity
var name = key.Name;
var owner = this;
int count = -1;
int position = 0;
var collisions = 0;
ResolveDelegate<BuilderContext>? pipeline = null;
ResolveDelegate<BuilderContext> buildPipeline;
var manager = null != factory.LifetimeManager && !(factory.LifetimeManager is TransientLifetimeManager)
? factory.LifetimeManager.CreateLifetimePolicy()
: null;
if (null != manager)
{
if (manager is IDisposable disposable) Context.Lifetime.Add(disposable);
if (manager is ContainerControlledLifetimeManager containerControlled) containerControlled.Scope = Context;
manager.PipelineDelegate = (ResolveDelegate<BuilderContext>)BuildPipeline;
buildPipeline = manager.Pipeline;
}
else
buildPipeline = BuildPipeline;
LifetimeManager manager;
// Add Pipeline to the Registry
lock (_syncLock)
@ -53,9 +37,8 @@ namespace Unity
continue;
}
Debug.Assert(null != candidate.Pipeline);
// Has already been created
Debug.Assert(null != candidate.Pipeline);
return candidate.Pipeline;
}
@ -66,53 +49,187 @@ namespace Unity
targetBucket = key.HashCode % _registry.Buckets.Length;
}
// Create a Lifetime Manager
manager = factory.LifetimeManager.CreateLifetimePolicy();
manager.PipelineDelegate = manager switch
{
TransientLifetimeManager transient => PipelineFromOpenGenericTransient(type, factory, transient, _registry.Count),
SynchronizedLifetimeManager synch => PipelineFromOpenGenericSynchronized(type, factory, synch),
PerResolveLifetimeManager peresolve => PipelineFromOpenGenericPerResolve(type, factory, peresolve),
_ => PipelineFromOpenGenericDefault(type, factory, manager)
};
// Create new entry
ref var entry = ref _registry.Entries[_registry.Count];
entry.Key = key;
entry.Type = type;
entry.Pipeline = buildPipeline;
entry.Pipeline = manager.Pipeline;
entry.Next = _registry.Buckets[targetBucket];
position = _registry.Count++;
_registry.Buckets[targetBucket] = position;
}
// Return temporary pipeline
return buildPipeline;
if (manager is IDisposable disposable) Context.Lifetime.Add(disposable);
// Return pipeline
return manager.Pipeline;
}
// Create pipeline and add to Registry
object? BuildPipeline(ref BuilderContext context)
private ResolveDelegate<BuilderContext> PipelineFromOpenGenericTransient(Type type, ExplicitRegistration factory, TransientLifetimeManager manager, int position)
{
ResolveDelegate<BuilderContext>? pipeline = null;
return (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
}
if (null != pipeline) return pipeline(ref context);
try
lock (manager)
{
// Create if required
if (null == pipeline)
{
PipelineBuilder builder = new PipelineBuilder(type, factory, manager, owner);
PipelineBuilder builder = new PipelineBuilder(type, factory, manager, this);
pipeline = builder.Pipeline();
if (null != manager) manager.PipelineDelegate = pipeline;
Debug.Assert(null != pipeline);
Debug.Assert(null != _registry);
// Replace pipeline in storage
lock (_syncLock)
{
_registry.Entries[position].Pipeline = pipeline;
}
}
var value = pipeline(ref context);
manager?.Set(value, LifetimeContainer);
return value;
return pipeline(ref context);
}
finally
};
}
private ResolveDelegate<BuilderContext> PipelineFromOpenGenericSynchronized(Type type, ExplicitRegistration factory, SynchronizedLifetimeManager manager)
{
ResolveDelegate<BuilderContext>? pipeline = null;
Debug.Assert(null != manager);
return (ref BuilderContext context) =>
{
object value;
if (null != pipeline)
{
Interlocked.Decrement(ref count);
value = manager.Get(LifetimeContainer);
if (LifetimeManager.NoValue != value) return value;
return pipeline(ref context);
}
lock (manager)
{
if (null == pipeline)
{
PipelineBuilder builder = new PipelineBuilder(type, factory, manager, this);
pipeline = builder.Pipeline();
manager.PipelineDelegate = pipeline;
Debug.Assert(null != pipeline);
}
}
value = manager.Get(LifetimeContainer);
if (LifetimeManager.NoValue != value) return value;
try
{
// Build withing the scope
return pipeline(ref context);
}
catch
{
manager.Recover();
throw;
}
};
}
private ResolveDelegate<BuilderContext> PipelineFromOpenGenericPerResolve(Type type, ExplicitRegistration factory, PerResolveLifetimeManager manager)
{
ResolveDelegate<BuilderContext>? pipeline = null;
return (ref BuilderContext context) =>
{
object value;
LifetimeManager? lifetime;
if (null != pipeline)
{
if (null != (lifetime = (LifetimeManager?)context.Get(typeof(LifetimeManager))))
{
value = lifetime.Get(LifetimeContainer);
if (LifetimeManager.NoValue != value) return value;
}
return pipeline(ref context);
}
lock (manager)
{
if (null == pipeline)
{
PipelineBuilder builder = new PipelineBuilder(type, factory, manager, this);
pipeline = builder.Pipeline();
manager.PipelineDelegate = pipeline;
Debug.Assert(null != pipeline);
value = pipeline(ref context);
context.Set(typeof(LifetimeManager), new RuntimePerResolveLifetimeManager(value));
return value;
}
}
if (null != (lifetime = (LifetimeManager?)context.Get(typeof(LifetimeManager))))
{
value = lifetime.Get(LifetimeContainer);
if (LifetimeManager.NoValue != value) return value;
}
return pipeline(ref context);
};
}
private ResolveDelegate<BuilderContext> PipelineFromOpenGenericDefault(Type type, ExplicitRegistration factory, LifetimeManager manager)
{
ResolveDelegate<BuilderContext>? pipeline = null;
return (ref BuilderContext context) =>
{
object value;
if (null != pipeline)
{
value = manager.Get(LifetimeContainer);
if (LifetimeManager.NoValue != value) return value;
return pipeline(ref context);
}
lock (manager)
{
if (null == pipeline)
{
PipelineBuilder builder = new PipelineBuilder(type, factory, manager, this);
pipeline = builder.Pipeline();
manager.PipelineDelegate = pipeline;
Debug.Assert(null != pipeline);
}
}
value = manager.Get(LifetimeContainer);
if (LifetimeManager.NoValue != value) return value;
return pipeline(ref context);
};
}
}

Просмотреть файл

@ -14,7 +14,6 @@ namespace Unity
{
Debug.Assert(null != _registry);
Debug.Assert(null != key.Type);
Debug.Assert(null != registration.LifetimeManager);
registration.LifetimeManager.PipelineDelegate = registration.LifetimeManager switch
{

Просмотреть файл

@ -56,7 +56,6 @@ namespace Unity
targetBucket = key.HashCode % _registry.Buckets.Length;
}
// Create a Lifetime Manager
manager = Context.TypeLifetimeManager.CreateLifetimePolicy();
manager.PipelineDelegate = manager switch

Просмотреть файл

@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using Unity.Lifetime;
using Unity.Policy;
using Unity.Registration;
using Unity.Storage;
@ -41,134 +37,6 @@ namespace Unity
#endregion
#region Getting Registration During Resolution
internal IRegistration GetRegistration(Type type, string? name)
{
#if NETSTANDARD1_0 || NETCOREAPP1_0
var info = type.GetTypeInfo();
return info.IsGenericType ? GetGenericRegistration(type, name, info) : GetSimpleRegistration(type, name);
#else
return type.IsGenericType ? GetGenericRegistration(type, name) : GetSimpleRegistration(type, name);
#endif
}
private IRegistration GetSimpleRegistration(Type type, string? name)
{
var key = new HashKey(type, 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;
Debug.Assert(null != container._registry);
var registry = container._registry;
// Check for exact match
for (var i = registry.Buckets[key.HashCode % registry.Buckets.Length]; 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);
return (IRegistration)candidate.Policies;
}
}
Debug.Assert(null != _root);
return _root.GetOrAdd(ref key, type, name, null);
}
#if NETSTANDARD1_0 || NETCOREAPP1_0
private IRegistration GetGenericRegistration(Type type, string? name, TypeInfo info)
#else
private IRegistration GetGenericRegistration(Type type, string? name)
#endif
{
bool initGenerics = true;
Type? generic = null;
int targetBucket;
var keyExact = new HashKey(type, name);
var keyGeneric = new HashKey();
var keyDefault = new HashKey();
// 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;
// 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;
// Found a registration
if (!(candidate.Policies is IRegistration))
candidate.Policies = container.CreateRegistration(type, name, candidate.Policies);
return (IRegistration)candidate.Policies;
}
// 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);
}
// 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.GetOrAdd(ref keyExact, type, name, candidate.Policies);
}
// 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.GetOrAdd(ref keyExact, type, name, candidate.Policies);
}
}
Debug.Assert(null != _root);
return _root.GetOrAdd(ref keyExact, type, name, null);
}
#endregion
#region Registration manipulation
private ExplicitRegistration? InitAndAdd(Type type, string? name, ExplicitRegistration registration)
@ -295,75 +163,6 @@ namespace Unity
return null;
}
private IEnumerable<IPolicySet> AddOrReplace(IEnumerable<Type> type, string? name, ExplicitRegistration registration)
{
throw new NotImplementedException();
}
private IRegistration GetOrAdd(ref HashKey key, Type type, string? name, IPolicySet? factory = null)
{
Debug.Assert(null != _registry);
lock (_syncLock)
{
var collisions = 0;
var targetBucket = key.HashCode % _registry.Buckets.Length;
// Check for the existing
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;
}
if (!(candidate.Policies is IRegistration))
candidate.Policies = CreateRegistration(type, name, candidate.Policies);
return (IRegistration)candidate.Policies;
}
// Expand if required
if (_registry.RequireToGrow || CollisionsCutPoint < collisions)
{
_registry = new Registry(_registry);
targetBucket = key.HashCode % _registry.Buckets.Length;
}
// Add registration
var registration = CreateRegistration(type, name, factory);
ref var entry = ref _registry.Entries[_registry.Count];
entry.Key = key;
entry.Type = type;
entry.Next = _registry.Buckets[targetBucket];
entry.Policies = registration;
_registry.Buckets[targetBucket] = _registry.Count++;
return (IRegistration)entry.Policies;
}
}
#endregion
#region Creating Implicit Registration
private IRegistration CreateRegistration(Type type, string? name, IPolicySet? set)
{
var registration = set is ImplicitRegistration factory
? new ImplicitRegistration(this, name, factory)
: new ImplicitRegistration(this, name, set);
registration.Processors = Context.TypePipelineCache;
if (registration.LifetimeManager is IDisposable) LifetimeContainer.Add(registration.LifetimeManager);
if (registration.LifetimeManager is ContainerControlledLifetimeManager manager) manager.Scope = this.Context;
return registration;
}
#endregion
}
}

Просмотреть файл

@ -75,7 +75,7 @@ namespace Unity
#region Resolving Enumerable
internal IEnumerable<TElement> ResolveEnumerable<TElement>(Func<Type, IRegistration, object?> resolve, string? name)
internal IEnumerable<TElement> ResolveEnumerable<TElement>(Func<Type, string?, object?> resolve, string? name)
{
object? value;
var set = new QuickSet();
@ -104,7 +104,7 @@ namespace Unity
try
{
value = resolve(typeof(TElement), registration);
value = resolve(typeof(TElement), registration.Name);
}
catch (ArgumentException ex) when (ex.InnerException is TypeLoadException)
{
@ -123,8 +123,7 @@ namespace Unity
{
try
{
var registration = GetRegistration(typeof(TElement), name);
value = resolve(typeof(TElement), registration);
value = resolve(typeof(TElement), name);
}
catch
{
@ -137,7 +136,7 @@ namespace Unity
}
}
internal IEnumerable<TElement> ResolveEnumerable<TElement>(Func<Type, IRegistration, object?> resolve,
internal IEnumerable<TElement> ResolveEnumerable<TElement>(Func<Type, string?, object?> resolve,
Type typeDefinition, string? name)
{
object? value;
@ -168,7 +167,7 @@ namespace Unity
try
{
value = resolve(typeof(TElement), registration);
value = resolve(typeof(TElement), registration.Name);
}
catch (ArgumentException ex) when (ex.InnerException is TypeLoadException)
{
@ -194,9 +193,7 @@ namespace Unity
{
try
{
var itemKey = new HashKey(typeof(TElement), registration.Name);
var item = container.GetOrAdd(ref itemKey, typeof(TElement), registration.Name, registration);
value = resolve(typeof(TElement), item);
value = resolve(typeof(TElement), registration.Name);
}
catch (MakeGenericTypeFailedException) { continue; }
catch (InvalidRegistrationException) { continue; }
@ -214,8 +211,7 @@ namespace Unity
{
try
{
var registration = GetRegistration(typeof(TElement), name);
value = resolve(typeof(TElement), registration);
value = resolve(typeof(TElement), name);
}
catch
{