Restore point
This commit is contained in:
Родитель
9dd0e2a620
Коммит
7c0a0afa69
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче