This commit is contained in:
Eugene Sadovoi 2019-06-05 18:30:19 -04:00
Родитель 896c609849
Коммит 9dd0e2a620
9 изменённых файлов: 242 добавлений и 110 удалений

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

@ -9,6 +9,7 @@ using Unity.Lifetime;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;
using Unity.Storage;
using static Unity.UnityContainer;
namespace Unity.Builder
@ -159,89 +160,7 @@ namespace Unity.Builder
#endregion
#region Public Methods
public object? Resolve(Type type)
{
// Process overrides if any
if (0 < Overrides.Length)
{
NamedType namedType = new NamedType
{
Type = type,
Name = Name
};
// Check if this parameter is overridden
for (var index = Overrides.Length - 1; index >= 0; --index)
{
var resolverOverride = Overrides[index];
// If matches with current parameter
if (resolverOverride is IResolve resolverPolicy &&
resolverOverride is IEquatable<NamedType> comparer && comparer.Equals(namedType))
{
var context = this;
return DependencyResolvePipeline(ref context, resolverPolicy.Resolve);
}
}
}
return Resolve(type, ((UnityContainer)Container).GetRegistration(type, Name));
}
public object? Resolve(Type type, IRegistration registration)
{
if (ReferenceEquals(Registration, registration)) throw new CircularDependencyException(type, registration.Name);
unsafe
{
var thisContext = this;
var context = new BuilderContext
{
ContainerContext = ContainerContext,
Registration = registration,
IsAsync = IsAsync,
Type = type,
List = List,
Overrides = Overrides,
DeclaringType = Type,
#if !NET40
Parent = new IntPtr(Unsafe.AsPointer(ref thisContext))
#endif
};
var manager = registration.LifetimeManager switch
{
null => TransientLifetimeManager.Instance,
PerResolveLifetimeManager _ => (LifetimeManager?)context.Get(typeof(LifetimeManager)) ??
TransientLifetimeManager.Instance,
_ => registration.LifetimeManager
};
// Check if already got value
var value = manager.GetValue(ContainerContext.Lifetime);
if (LifetimeManager.NoValue != value) return value;
if (registration.LifetimeManager is SynchronizedLifetimeManager synchronized)
{
try
{
value = context.Pipeline(ref context);
}
catch
{
synchronized.Recover();
throw;
}
}
else
value = context.Pipeline(ref context);
manager.SetValue(value, ContainerContext.Lifetime);
return value;
}
}
#region Member Resolution
public object? Resolve(ParameterInfo parameter, object? value)
{
@ -397,5 +316,126 @@ namespace Unity.Builder
}
#endregion
#region Public Methods
public object? Resolve(Type type)
{
// Process overrides if any
if (0 < Overrides.Length)
{
NamedType namedType = new NamedType
{
Type = type,
Name = Name
};
// Check if this parameter is overridden
for (var index = Overrides.Length - 1; index >= 0; --index)
{
var resolverOverride = Overrides[index];
// If matches with current parameter
if (resolverOverride is IResolve resolverPolicy &&
resolverOverride is IEquatable<NamedType> comparer && comparer.Equals(namedType))
{
var context = this;
return DependencyResolvePipeline(ref context, resolverPolicy.Resolve);
}
}
}
var key = new HashKey(type, Name);
return Resolve(ContainerContext.Container.GetPipeline(ref key));
}
public object? Resolve(Type type, IRegistration registration)
{
if (ReferenceEquals(Registration, registration)) throw new CircularDependencyException(type, registration.Name);
unsafe
{
var thisContext = this;
var container = registration.LifetimeManager is ContainerControlledLifetimeManager containerControlled
? (ContainerContext)containerControlled.Scope
: ContainerContext;
var context = new BuilderContext
{
ContainerContext = container,
Registration = registration,
IsAsync = IsAsync,
Type = type,
List = List,
Overrides = Overrides,
DeclaringType = Type,
#if !NET40
Parent = new IntPtr(Unsafe.AsPointer(ref thisContext))
#endif
};
var manager = registration.LifetimeManager switch
{
null => TransientLifetimeManager.Instance,
PerResolveLifetimeManager _ => (LifetimeManager?)context.Get(typeof(LifetimeManager)) ??
TransientLifetimeManager.Instance,
_ => registration.LifetimeManager
};
// Check if already got value
var value = manager.GetValue(ContainerContext.Lifetime);
if (LifetimeManager.NoValue != value) return value;
if (registration.LifetimeManager is SynchronizedLifetimeManager synchronized)
{
try
{
value = context.Pipeline(ref context);
}
catch
{
synchronized.Recover();
throw;
}
}
else
value = context.Pipeline(ref context);
manager.SetValue(value, ContainerContext.Lifetime);
return value;
}
}
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 thisContext = this;
try
{
// Execute pipeline
var value = pipeline(ref thisContext);
manager?.Set(value, ContainerContext.Lifetime);
return value;
}
catch when (null != synchronized)
{
synchronized.Recover();
throw;
}
}
#endregion
}
}

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

@ -34,13 +34,17 @@ namespace Unity
public PipelineBuilder(Type type, UnityContainer container, IEnumerable<Pipeline> pipelines)
{
Type = type;
BuildType = null;
TypeConverter = null;
BuildRequired = false;
LifetimeManager = null;
InjectionMembers = null;
Factory = null;
Policies = null;
Registration = null;
IsMapping = false;
BuildRequired = false;
ContainerContext = container.Context;
Seed = null;
@ -48,18 +52,22 @@ namespace Unity
}
// Pipeline From Registration
public PipelineBuilder(ExplicitRegistration registration)
public PipelineBuilder(Type type, ExplicitRegistration registration)
{
Debug.Assert(null != registration.Type);
Type = registration.Type;
BuildType = null;
Type = type;
TypeConverter = null;
BuildRequired = registration.BuildRequired;
LifetimeManager = registration.LifetimeManager;
InjectionMembers = registration.InjectionMembers;
Factory = null;
Policies = registration;
Registration = registration;
IsMapping = null != registration.Type && type != registration.Type;
BuildRequired = registration.BuildRequired;
Seed = registration.Pipeline;
ContainerContext = registration.Owner.Context;
@ -71,14 +79,19 @@ namespace Unity
// Pipeline from context
public PipelineBuilder(ref BuilderContext context)
{
var type = (context.Registration as ExplicitRegistration)?.Type ?? context.Type;
Type = context.Type;
BuildType = (context.Registration as ExplicitRegistration)?.Type;
TypeConverter = context.Registration?.BuildType;
BuildRequired = context.Registration?.BuildRequired ?? false;
LifetimeManager = context.Registration?.LifetimeManager;
InjectionMembers = context.Registration?.InjectionMembers;
Policies = context.Registration;
Registration = context.Registration as ExplicitRegistration;
Factory = null != Registration ? null : context.Registration as ImplicitRegistration;
Policies = Registration ?? Factory;
IsMapping = (null != Registration?.Type && Registration?.Type != Type) || null != Factory?.BuildType;
BuildRequired = context.Registration?.BuildRequired ?? false;
ContainerContext = context.ContainerContext;
Seed = context.Registration?.Pipeline;
@ -91,15 +104,18 @@ namespace Unity
public PipelineBuilder(Type type, ExplicitRegistration factory, UnityContainer owner)
{
Type = type;
BuildType = factory.Type;
Seed = factory.Pipeline;
TypeConverter = factory.BuildType;
// TODO: Move to registration
BuildRequired = null != factory.InjectionMembers && factory.InjectionMembers.Any(m => m.BuildRequired);
LifetimeManager = factory.LifetimeManager?.CreateLifetimePolicy();
InjectionMembers = factory.InjectionMembers;
Policies = null;
Factory = factory;
Policies = factory;
Registration = null;
IsMapping = null != factory.BuildType;
// TODO: Move to registration
BuildRequired = null != factory.InjectionMembers && factory.InjectionMembers.Any(m => m.BuildRequired);
ContainerContext = owner.Context;
@ -114,12 +130,17 @@ namespace Unity
public Type Type;
public readonly Type? BuildType;
public LifetimeManager? LifetimeManager { get; }
public InjectionMember[]? InjectionMembers { get; set; }
public ExplicitRegistration? Registration { get; }
public ImplicitRegistration? Factory { get; }
public bool IsMapping { get; }
public bool BuildRequired { get; }
public Converter<Type, Type>? TypeConverter { get; }

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

@ -0,0 +1,44 @@
using System.Diagnostics;
using Unity.Builder;
using Unity.Lifetime;
using Unity.Resolution;
using static Unity.UnityContainer;
namespace Unity
{
public class LifetimePipeline : Pipeline
{
#region PipelineBuilder
public override ResolveDelegate<BuilderContext>? Build(ref PipelineBuilder builder)
{
if (builder.LifetimeManager is ContainerControlledLifetimeManager manager)
{
var pipeline = builder.Pipeline();
Debug.Assert(null != pipeline);
return (ref BuilderContext context) =>
{
var scope = context.ContainerContext;
try
{
// Switch context to lifetime's scope
context.ContainerContext = (ContainerContext)manager.Scope;
// Build withing the scope
return pipeline(ref context);
}
finally
{
context.ContainerContext = scope;
}
};
}
return builder.Pipeline(); ;
}
#endregion
}
}

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

@ -1,5 +1,4 @@
using Unity.Builder;
using Unity.Registration;
using Unity.Resolution;
namespace Unity
@ -10,16 +9,16 @@ namespace Unity
public override ResolveDelegate<BuilderContext>? Build(ref PipelineBuilder builder)
{
if (!builder.IsMapping) return builder.Pipeline();
var requestedType = builder.Type;
if (builder.Policies is ExplicitRegistration @explicit)
if (null != builder.Registration)
{
// Explicit Registration
if (null == @explicit.Type) return builder.Pipeline();
if (null == builder.Registration.Type) return builder.Pipeline();
builder.Type = (null == @explicit.BuildType)
? @explicit.Type
: @explicit.BuildType(@explicit.Type);
builder.Type = builder.Registration.Type;
}
else if (null != builder.TypeConverter)
{

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

@ -31,6 +31,9 @@ namespace Unity.Registration
LifetimeManager = lifetimeManager;
InjectionMembers = null;
BuildRequired = null != InjectionMembers && InjectionMembers.Any(m => m.BuildRequired);
if (lifetimeManager is ContainerControlledLifetimeManager manager)
manager.Scope = owner.Context;
}
public ExplicitRegistration(UnityContainer owner, string? name, Type? type, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
@ -42,6 +45,9 @@ namespace Unity.Registration
InjectionMembers = null != injectionMembers && 0 < injectionMembers.Length ? injectionMembers : null;
BuildRequired = null != InjectionMembers && InjectionMembers.Any(m => m.BuildRequired) || lifetimeManager is PerResolveLifetimeManager;
BuildType = GetTypeConverter();
if (lifetimeManager is ContainerControlledLifetimeManager manager)
manager.Scope = owner.Context;
}
#endregion

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

@ -202,7 +202,6 @@ namespace Unity
#region Getting objects
/*
/// <inheritdoc />
[SecuritySafeCritical]
object? IUnityContainer.Resolve(Type type, string? name, params ResolverOverride[] overrides)
@ -250,7 +249,7 @@ namespace Unity
else throw;
}
}
*/
/*
/// <inheritdoc />
[SecuritySafeCritical]
object? IUnityContainer.Resolve(Type type, string? name, params ResolverOverride[] overrides)
@ -296,6 +295,7 @@ namespace Unity
else throw;
}
}
*/
#endregion

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

@ -39,7 +39,7 @@ namespace Unity
return null;
}
private ResolveDelegate<BuilderContext> GetPipeline(ref HashKey key)
internal ResolveDelegate<BuilderContext> GetPipeline(ref HashKey key)
{
#if NETSTANDARD1_0 || NETCOREAPP1_0
var info = key.Type?.GetTypeInfo();
@ -268,6 +268,12 @@ namespace Unity
var name = key.Name;
ResolveDelegate<BuilderContext>? pipeline = null;
if (null != registration.LifetimeManager && !(registration.LifetimeManager is TransientLifetimeManager))
{
registration.LifetimeManager.PipelineDelegate = (ResolveDelegate<BuilderContext>)BuildPipeline;
return registration.LifetimeManager.Pipeline;
}
return BuildPipeline;
object? BuildPipeline(ref BuilderContext context)
@ -277,7 +283,7 @@ namespace Unity
{
if (null != pipeline) return pipeline(ref context);
PipelineBuilder builder = new PipelineBuilder(registration);
PipelineBuilder builder = new PipelineBuilder(type, registration);
if (registration.LifetimeManager is LifetimeManager manager)
{
@ -324,6 +330,18 @@ namespace Unity
int position = 0;
var collisions = 0;
ResolveDelegate<BuilderContext>? pipeline = null;
ResolveDelegate<BuilderContext> buildPipeline = null;
if (null != factory.LifetimeManager && !(factory.LifetimeManager is TransientLifetimeManager))
{
var manager = factory.LifetimeManager.CreateLifetimePolicy();
if (manager is ContainerControlledLifetimeManager containerControlled) containerControlled.Scope = this;
manager.PipelineDelegate = (ResolveDelegate<BuilderContext>)BuildPipeline;
buildPipeline = manager.Pipeline;
}
else
buildPipeline = BuildPipeline;
// Add Pipeline to the Registry
lock (_syncLock)
@ -355,14 +373,14 @@ namespace Unity
ref var entry = ref _registry.Entries[_registry.Count];
entry.Key = key;
entry.Type = type;
entry.Pipeline = BuildPipeline;
entry.Pipeline = buildPipeline;
entry.Next = _registry.Buckets[targetBucket];
position = _registry.Count++;
_registry.Buckets[targetBucket] = position;
}
// Return temporary pipeline
return BuildPipeline;
return buildPipeline;
// Create pipeline and add to Registry

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

@ -90,6 +90,7 @@ namespace Unity
// Pipelines
var factory = new FactoryPipeline();
var lifetime = new LifetimePipeline();
// Mode of operation
if (ExecutionMode.IsOptimized())
@ -102,6 +103,7 @@ namespace Unity
Context = new ContainerContext(this,
new StagedStrategyChain<Pipeline, Stage> // Type Build Pipeline
{
{ lifetime, Stage.Lifetime },
{ factory, Stage.Factory },
{ new MappingPipeline(), Stage.TypeMapping },
{ new ConstructorPipeline(this), Stage.Creation },
@ -111,6 +113,7 @@ namespace Unity
},
new StagedStrategyChain<Pipeline, Stage> // Factory Resolve Pipeline
{
{ lifetime, Stage.Lifetime },
{ factory, Stage.Factory }
},
new StagedStrategyChain<Pipeline, Stage> // Instance Resolve Pipeline

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

@ -359,6 +359,7 @@ namespace Unity
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;
}