This commit is contained in:
Eugene Sadovoi 2019-06-05 23:26:56 -04:00
Родитель 9dd0e2a620
Коммит 7c0a0afa69
8 изменённых файлов: 147 добавлений и 74 удалений

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

@ -35,7 +35,7 @@ namespace Unity.Builder
public Type Type { get; set; }
public string? Name => Registration?.Name;
public string? Name { get; set; }
public object? Resolve(Type type, string? name)
{
@ -63,7 +63,24 @@ namespace Unity.Builder
}
}
return Resolve(type, ((UnityContainer)Container).GetRegistration(type, name));
var key = new HashKey(type, name);
var pipeline = ContainerContext.Container.GetPipeline(ref key);
LifetimeManager? manager = pipeline.Target as LifetimeManager;
// Check if already created and acquire a lock if not
if (manager is PerResolveLifetimeManager)
{
manager = List.Get(type, name, typeof(LifetimeManager)) as LifetimeManager ?? manager;
}
if (null != manager)
{
// Make blocking check for result
var value = manager.Get(ContainerContext.Lifetime);
if (LifetimeManager.NoValue != value) return value;
}
return Resolve(pipeline);
}
#endregion
@ -346,8 +363,25 @@ namespace Unity.Builder
}
}
var key = new HashKey(type, Name);
return Resolve(ContainerContext.Container.GetPipeline(ref key));
var pipeline = ContainerContext.Container.GetPipeline(ref key);
LifetimeManager? manager = pipeline.Target as LifetimeManager;
// Check if already created and acquire a lock if not
if (manager is PerResolveLifetimeManager)
{
manager = List.Get(type, Name, typeof(LifetimeManager)) as LifetimeManager ?? manager;
}
if (null != manager)
{
// Make blocking check for result
var value = manager.Get(ContainerContext.Lifetime);
if (LifetimeManager.NoValue != value) return value;
}
return Resolve(pipeline);
}
public object? Resolve(Type type, IRegistration registration)
@ -409,24 +443,15 @@ namespace Unity.Builder
public object? Resolve(ResolveDelegate<BuilderContext> pipeline)
{
// Check if already created and acquire a lock if not
var manager = pipeline.Target as LifetimeManager;
if (null != manager)
{
// Make blocking check for result
var value = manager.Get(ContainerContext.Lifetime);
if (LifetimeManager.NoValue != value) return value;
}
// Setup Context
var synchronized = manager as SynchronizedLifetimeManager;
var synchronized = pipeline.Target as SynchronizedLifetimeManager;
var thisContext = this;
try
{
// Execute pipeline
var value = pipeline(ref thisContext);
manager?.Set(value, ContainerContext.Lifetime);
(pipeline.Target as LifetimeManager)?.Set(value, ContainerContext.Lifetime);
return value;
}
catch when (null != synchronized)

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

@ -30,6 +30,7 @@ namespace Unity.Factories
#region Implementation
// TODO: Add PerResolve handler
private static Func<T> ResolverImplementation<T>(ref BuilderContext context)
{
var nameToBuild = context.Name;

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

@ -2,9 +2,7 @@
using System.Reflection;
using Unity.Builder;
using Unity.Lifetime;
using Unity.Registration;
using Unity.Resolution;
using Unity.Storage;
namespace Unity.Factories
{

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

@ -2,7 +2,6 @@
using System.Linq;
using System.Reflection;
using Unity.Builder;
using Unity.Registration;
using Unity.Resolution;
namespace Unity.Factories

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

@ -101,12 +101,12 @@ namespace Unity
}
// Pipeline from factory
public PipelineBuilder(Type type, ExplicitRegistration factory, UnityContainer owner)
public PipelineBuilder(Type type, ExplicitRegistration factory, LifetimeManager manager, UnityContainer owner)
{
Type = type;
Seed = factory.Pipeline;
TypeConverter = factory.BuildType;
LifetimeManager = factory.LifetimeManager?.CreateLifetimePolicy();
LifetimeManager = manager;
InjectionMembers = factory.InjectionMembers;
Factory = factory;

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

@ -224,6 +224,7 @@ namespace Unity
{
List = new PolicyList(),
Type = type,
Name = name,
Overrides = overrides,
ContainerContext = Context,
};
@ -249,53 +250,6 @@ namespace Unity
else throw;
}
}
/*
/// <inheritdoc />
[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;
}
}
*/
#endregion
@ -306,14 +260,17 @@ namespace Unity
[SecuritySafeCritical]
public object? BuildUp(Type type, object existing, string? name, params ResolverOverride[] overrides)
{
var key = new HashKey(type ?? throw new ArgumentNullException(nameof(type)), name);
var pipeline = GetPipeline(ref key);
// Setup Context
var context = new BuilderContext
{
Existing = existing ?? throw new ArgumentNullException(nameof(existing)),
List = new PolicyList(),
Type = ValidateType(type, existing.GetType()),
Name = name,
Overrides = overrides,
Registration = GetRegistration(type ?? throw new ArgumentNullException(nameof(type)), name),
ContainerContext = Context,
};
@ -321,7 +278,7 @@ namespace Unity
try
{
// Execute pipeline
return context.Pipeline(ref context);
return pipeline(ref context);
}
catch (Exception ex)
when (ex is InvalidRegistrationException || ex is CircularDependencyException || ex is ObjectDisposedException)

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

@ -282,6 +282,7 @@ namespace Unity
{
List = new PolicyList(),
Type = type,
Name = name,
Overrides = overrides,
Registration = registration,
ContainerContext = Context,

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

@ -161,7 +161,8 @@ namespace Unity
continue;
// Found a factory
return container.PipelineFromFactory(ref key, (ExplicitRegistration)candidate.Policies);
var typeFactory = (TypeFactoryDelegate)candidate.Policies.Get(typeof(TypeFactoryDelegate));
return container.PipelineFromTypeFactory(ref key, container, typeFactory);
}
}
@ -330,12 +331,15 @@ namespace Unity
int position = 0;
var collisions = 0;
ResolveDelegate<BuilderContext>? pipeline = null;
ResolveDelegate<BuilderContext> buildPipeline = null;
ResolveDelegate<BuilderContext> buildPipeline;
var manager = null != factory.LifetimeManager && !(factory.LifetimeManager is TransientLifetimeManager)
? factory.LifetimeManager.CreateLifetimePolicy()
: null;
if (null != factory.LifetimeManager && !(factory.LifetimeManager is TransientLifetimeManager))
if (null != manager)
{
var manager = factory.LifetimeManager.CreateLifetimePolicy();
if (manager is ContainerControlledLifetimeManager containerControlled) containerControlled.Scope = this;
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;
@ -402,9 +406,97 @@ namespace Unity
// Create if required
if (null == pipeline)
{
PipelineBuilder builder = new PipelineBuilder(type, factory, owner);
PipelineBuilder builder = new PipelineBuilder(type, factory, manager, owner);
pipeline = builder.Pipeline();
if (null != manager) manager.PipelineDelegate = pipeline;
Debug.Assert(null != pipeline);
}
var value = pipeline(ref context);
manager?.Set(value, LifetimeContainer);
return value;
}
finally
{
Interlocked.Decrement(ref count);
}
};
}
private ResolveDelegate<BuilderContext> PipelineFromTypeFactory(ref HashKey key, UnityContainer container, TypeFactoryDelegate typeFactory)
{
Debug.Assert(null != _registry);
Debug.Assert(null != key.Type);
var type = key.Type;
var name = key.Name;
var owner = this;
int count = -1;
int position = 0;
var collisions = 0;
ResolveDelegate<BuilderContext>? 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)
{
pipeline = typeFactory(type, container);
Debug.Assert(null != pipeline);
}