Attempting to remove registration for implicit types

This commit is contained in:
Eugene Sadovoi 2019-05-21 17:16:07 -04:00
Родитель cdadd81f96
Коммит bacb641231
24 изменённых файлов: 296 добавлений и 69 удалений

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

@ -0,0 +1,22 @@
using System;
using System.Text.RegularExpressions;
using Unity.Resolution;
namespace Unity
{
public struct PipelineContext
{
#region Public Properties
public bool RunAsync;
public Type Type;
public string? Name;
public Regex Regex;
public object? Existing;
public bool RunningAsync;
public ResolverOverride[] Overrides;
public UnityContainer.ContainerContext ContainerContext;
#endregion
}
}

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

@ -0,0 +1,6 @@
using System.Threading.Tasks;
namespace Unity
{
public delegate ValueTask<object?> BuildPipelineAsync(ref PipelineContext context);
}

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

@ -1,10 +1,10 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Unity.Policy;
using Unity.Registration;
namespace Unity
{
public delegate IEnumerable<object> MemberSelector<TMember>(Type type, IPolicySet set)
public delegate IEnumerable<object> MemberSelector<TMember>(Type type, IRegistration set)
where TMember : MemberInfo;
}

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

@ -12,7 +12,7 @@ namespace Unity
#region Public Members
public virtual IEnumerable<Expression> Build(UnityContainer container, IEnumerator<Pipeline> enumerator,
Type type, ImplicitRegistration registration) => throw new NotImplementedException();
Type type, IRegistration registration) => throw new NotImplementedException();
public virtual ResolveDelegate<BuilderContext>? Build(ref PipelineBuilder builder) => builder.Pipeline();

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

@ -25,12 +25,13 @@ namespace Unity
#endregion
#region Constructors
public PipelineBuilder(ExplicitRegistration registration, UnityContainer container, IEnumerable<Pipeline> pipelines)
{
Type = registration.Type ?? typeof(object);
Name = registration.Name;
Registration = registration;
ContainerContext = container.Context;
@ -38,9 +39,24 @@ namespace Unity
_enumerator = pipelines.GetEnumerator();
}
public PipelineBuilder(ref PipelineContext context)
{
Seed = null;
Type = context.Type;
Name = context.Name;
Registration = null;
ContainerContext = context.ContainerContext;
_enumerator = context.ContainerContext
.TypePipelineCache
.AsEnumerable<Pipeline>()
.GetEnumerator();
}
public PipelineBuilder(ref BuilderContext context)
{
Type = context.Type;
Name = context.Name;
Registration = context.Registration;
ContainerContext = context.ContainerContext;
@ -55,13 +71,13 @@ namespace Unity
public Type Type;
public string? Name => Registration.Name;
public string? Name { get; }
public ResolveDelegate<BuilderContext>? Seed { get; private set; }
public readonly ContainerContext ContainerContext;
public readonly IRegistration Registration;
public readonly IRegistration? Registration;
#endregion
@ -88,7 +104,9 @@ namespace Unity
public PipelineDelegate PipelineDelegate()
{
return Registration.LifetimeManager switch
var manager = Registration?.LifetimeManager;
return manager switch
{
null => TransientLifetime(),
TransientLifetimeManager _ => TransientLifetime(),

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

@ -9,7 +9,6 @@ using Unity.Builder;
using Unity.Exceptions;
using Unity.Injection;
using Unity.Lifetime;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;
@ -76,12 +75,12 @@ namespace Unity
#region Selection
public override IEnumerable<object> Select(Type type, IPolicySet registration)
public override IEnumerable<object> Select(Type type, IRegistration registration)
{
var members = new List<InjectionMember>();
// Select Injected Members
foreach (var injectionMember in ((ImplicitRegistration)registration).InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<ConstructorInfo, object[]>)
{

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

@ -4,7 +4,6 @@ using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Unity.Builder;
using Unity.Exceptions;
using Unity.Lifetime;
using Unity.Registration;
@ -37,7 +36,7 @@ namespace Unity
#region PipelineBuilder
public override IEnumerable<Expression> Build(UnityContainer container, IEnumerator<Pipeline> enumerator,
Type type, ImplicitRegistration registration)
Type type, IRegistration registration)
{
//// Select ConstructorInfo
//var selector = GetOrDefault(registration);

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

@ -39,8 +39,8 @@ namespace Unity
}
// Select ConstructorInfo
var selector = GetOrDefault((IPolicySet)builder.Registration);
var selection = selector.Invoke(builder.Type, (IPolicySet)builder.Registration)
var selector = GetOrDefault(builder.Registration);
var selection = selector.Invoke(builder.Type, builder.Registration)
.FirstOrDefault();
// Select constructor for the Type

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

@ -5,7 +5,6 @@ using System.Linq;
using System.Reflection;
using Unity.Exceptions;
using Unity.Injection;
using Unity.Policy;
using Unity.Registration;
namespace Unity
@ -13,10 +12,10 @@ namespace Unity
public partial class ConstructorPipeline
{
public override IEnumerable<object> Select(Type type, IPolicySet registration)
public override IEnumerable<object> Select(Type type, IRegistration registration)
{
// Select Injected Members
foreach (var injectionMember in ((ImplicitRegistration)registration).InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<ConstructorInfo, object[]>)
{

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

@ -16,7 +16,7 @@ namespace Unity
#region PipelineBuilder
public override IEnumerable<Expression> Build(UnityContainer container, IEnumerator<Pipeline> enumerator,
Type type, ImplicitRegistration registration)
Type type, IRegistration registration)
{
yield break;
}

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

@ -3,11 +3,10 @@ using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using Unity.Builder;
using Unity.Exceptions;
using Unity.Injection;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;
using Unity.Exceptions;
namespace Unity
{
@ -25,12 +24,12 @@ namespace Unity
#region Overrides
public override IEnumerable<object> Select(Type type, IPolicySet registration)
public override IEnumerable<object> Select(Type type, IRegistration registration)
{
HashSet<object> memberSet = new HashSet<object>();
// Select Injected Members
foreach (var injectionMember in ((ImplicitRegistration)registration).InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<FieldInfo, object> && memberSet.Add(injectionMember))
yield return injectionMember;

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

@ -12,7 +12,7 @@ namespace Unity
#region PipelineBuilder
public override IEnumerable<Expression> Build(UnityContainer container, IEnumerator<Pipeline> enumerator,
Type type, ImplicitRegistration registration)
Type type, IRegistration registration)
{
yield break;
}

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

@ -125,7 +125,7 @@ namespace Unity
/// <param name="type"></param>
/// <param name="registration"></param>
/// <returns></returns>
public IEnumerable<Expression> GetExpressions(Type type, ImplicitRegistration registration)
public IEnumerable<Expression> GetExpressions(Type type, IRegistration registration)
{
var selector = GetOrDefault(registration);
var members = selector(type, registration);

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

@ -2,19 +2,18 @@
using System.Collections.Generic;
using System.Reflection;
using Unity.Injection;
using Unity.Policy;
using Unity.Registration;
namespace Unity
{
public abstract partial class MemberPipeline<TMemberInfo, TData>
{
public virtual IEnumerable<object> Select(Type type, IPolicySet registration)
public virtual IEnumerable<object> Select(Type type, IRegistration registration)
{
HashSet<object> memberSet = new HashSet<object>();
// Select Injected Members
foreach (var injectionMember in ((ImplicitRegistration)registration).InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<TMemberInfo, TData> && memberSet.Add(injectionMember))
yield return injectionMember;

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

@ -6,7 +6,6 @@ using System.Reflection;
using Unity.Builder;
using Unity.Exceptions;
using Unity.Injection;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;
@ -27,12 +26,12 @@ namespace Unity
#region Overrides
public override IEnumerable<object> Select(Type type, IPolicySet registration)
public override IEnumerable<object> Select(Type type, IRegistration registration)
{
HashSet<object> memberSet = new HashSet<object>();
// Select Injected Members
foreach (var injectionMember in ((ImplicitRegistration)registration).InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<MethodInfo, object[]> && memberSet.Add(injectionMember))
yield return injectionMember;

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

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Reflection;
using Unity.Injection;
using Unity.Policy;
using Unity.Registration;
namespace Unity
@ -10,12 +9,12 @@ namespace Unity
public partial class MethodPipeline
{
public override IEnumerable<object> Select(Type type, IPolicySet registration)
public override IEnumerable<object> Select(Type type, IRegistration registration)
{
HashSet<object> memberSet = new HashSet<object>();
// Select Injected Members
foreach (var injectionMember in ((ImplicitRegistration)registration).InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<MethodInfo, object[]> && memberSet.Add(injectionMember))
yield return injectionMember;

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

@ -5,7 +5,6 @@ using System.Reflection;
using Unity.Builder;
using Unity.Exceptions;
using Unity.Injection;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;
@ -26,12 +25,12 @@ namespace Unity
#region Overrides
public override IEnumerable<object> Select(Type type, IPolicySet registration)
public override IEnumerable<object> Select(Type type, IRegistration registration)
{
HashSet<object> memberSet = new HashSet<object>();
// Select Injected Members
foreach (var injectionMember in ((ImplicitRegistration)registration).InjectionMembers ?? EmptyCollection)
foreach (var injectionMember in registration.InjectionMembers ?? EmptyCollection)
{
if (injectionMember is InjectionMember<PropertyInfo, object> && memberSet.Add(injectionMember))
yield return injectionMember;

135
src/Storage/Pipelines.cs Normal file
Просмотреть файл

@ -0,0 +1,135 @@
using System;
using System.Diagnostics;
using System.Security;
using Unity.Policy;
using Unity.Registration;
namespace Unity.Storage
{
[SecuritySafeCritical]
public class Pipelines
{
#region Fields
private readonly int _prime;
public readonly int[] Buckets;
public readonly Entry[] Entries;
public int Count;
#endregion
#region Constructors
public Pipelines()
{
var size = Primes[0];
Buckets = new int[size];
Entries = new Entry[size];
Count = 0;
#if !NET40
unsafe
{
fixed (int* bucketsPtr = Buckets)
{
int* ptr = bucketsPtr;
var end = bucketsPtr + Buckets.Length;
while (ptr < end) *ptr++ = -1;
}
}
#else
for(int i = 0; i < Buckets.Length; i++)
Buckets[i] = -1;
#endif
}
public Pipelines(int prime)
{
if (prime < 0 || prime >= Primes.Length) throw new ArgumentException("Capacity Overflow");
_prime = prime;
var size = Primes[_prime];
Buckets = new int[size];
Entries = new Entry[size];
#if !NET40
unsafe
{
fixed (int* bucketsPtr = Buckets)
{
int* ptr = bucketsPtr;
var end = bucketsPtr + Buckets.Length;
while (ptr < end) *ptr++ = -1;
}
}
#else
for(int i = 0; i < Buckets.Length; i++)
Buckets[i] = -1;
#endif
}
public Pipelines(Pipelines Pipelines)
: this(Pipelines._prime + 1)
{
Array.Copy(Pipelines.Entries, 0, Entries, 0, Pipelines.Count);
for (var i = 0; i < Pipelines.Count; i++)
{
var hashCode = Entries[i].Key.HashCode;
if (hashCode < 0) continue;
var bucket = hashCode % Buckets.Length;
Entries[i].Next = Buckets[bucket];
Buckets[bucket] = i;
}
Count = Pipelines.Count;
}
public Pipelines(BuildPipelineAsync value)
: this(0)
{
ref var entry = ref Entries[0];
entry.Next = -1;
entry.Pipeline = value;
Buckets[0] = 0;
Count++;
}
#endregion
#region Public Members
public bool RequireToGrow => (Entries.Length - Count) < 100 &&
(float)Count / Entries.Length > 0.72f;
#endregion
#region Entry Type
public struct Entry
{
public HashKey Key;
public int Next;
public BuildPipelineAsync Pipeline;
}
#endregion
#region Prime Numbers
public static readonly int[] Primes = {
37, 71, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, 1103, 1327, 1597,
1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, 17519, 21023,
25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, 187751,
225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};
#endregion
}
}

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

@ -192,27 +192,33 @@ namespace Unity
ValueTask<object?> IUnityContainerAsync.ResolveAsync(Type type, string? name, params ResolverOverride[] overrides)
{
// Setup Context
var registration = GetRegistration(type ?? throw new ArgumentNullException(nameof(type)), name);
var pipeline = GetPipeline(type ?? throw new ArgumentNullException(nameof(type)), name);
// Check if pipeline exists
if (null == registration.Pipeline && !(registration.LifetimeManager is PerThreadLifetimeManager))
if (null == pipeline)
{
// Start a new Task to create and execute pipeline
var task = Task.Factory.StartNew(() =>
{
var context = new BuilderContext
Debug.Assert(null != _root);
Debug.Assert(null != _root._pipelines);
// Get pipeline builder
pipeline = _root._pipelines.Entries[0].Pipeline;
var context = new PipelineContext
{
Type = type,
IsAsync = true,
Name = name,
RunningAsync = true,
Overrides = overrides,
Registration = registration,
ContainerContext = Context,
};
try
{
// Execute pipeline
return context.Pipeline(ref context).Result;
return pipeline(ref context).Result;
}
catch (Exception ex)
when (ex is InvalidRegistrationException ||
@ -227,21 +233,19 @@ namespace Unity
return new ValueTask<object?>(task);
}
// Existing pipeline
var context = new BuilderContext
// Execute pipeline
var context = new PipelineContext
{
Async = true,
Type = type,
Name = name,
RunAsync = true,
Overrides = overrides,
Registration = registration,
ContainerContext = Context,
};
try
{
// Execute pipeline
return context.Pipeline(ref context);
return pipeline(ref context);
}
catch (Exception ex)
when (ex is InvalidRegistrationException ||

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

@ -12,7 +12,6 @@ using Unity.Events;
using Unity.Exceptions;
using Unity.Extension;
using Unity.Lifetime;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;
using Unity.Storage;
@ -41,6 +40,7 @@ namespace Unity
// Essentials
private Metadata? _metadata;
private Registry? _registry;
private Pipelines? _pipelines;
private readonly UnityContainer _root;
private readonly UnityContainer? _parent;
@ -72,8 +72,8 @@ namespace Unity
private UnityContainer(UnityContainer parent)
{
// Validate input
Debug.Assert(null != parent, nameof(parent));
Debug.Assert(null != parent._root, nameof(parent._root));
Debug.Assert(null != parent);
Debug.Assert(null != parent._root);
// Register with parent
_parent = parent;

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

@ -0,0 +1,51 @@
using System;
using System.Diagnostics;
using System.Security;
using System.Threading.Tasks;
using Unity.Builder;
using Unity.Storage;
namespace Unity
{
public partial class UnityContainer
{
private BuildPipelineAsync? GetPipeline(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 the parent if no pipelines
if (null == container._pipelines) continue;
var registry = container._pipelines;
// 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 it
return candidate.Pipeline;
}
}
return null;
}
#region Root Build Pipeline
[SecuritySafeCritical]
public ValueTask<object?> DefaultBuildPipeline(ref PipelineContext context)
{
var builder = new PipelineBuilder(ref PipelineContext context);
throw new NotImplementedException();
}
#endregion
}
}

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

@ -67,8 +67,9 @@ namespace Unity
};
// Create Registry
_metadata = new Metadata();
_registry = new Registry(Defaults);
_metadata = new Metadata();
_registry = new Registry(Defaults);
_pipelines = new Pipelines(DefaultBuildPipeline);
_registry.Set(typeof(IUnityContainer), null, container);
_registry.Set(typeof(IUnityContainerAsync), null, container);

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

@ -43,7 +43,7 @@ namespace Unity
#region Getting Registration During Resolution
internal ImplicitRegistration GetRegistration(Type type, string? name)
internal IRegistration GetRegistration(Type type, string? name)
{
#if NETSTANDARD1_0 || NETCOREAPP1_0
var info = type.GetTypeInfo();
@ -53,7 +53,7 @@ namespace Unity
#endif
}
private ImplicitRegistration GetSimpleRegistration(Type type, string? name)
private IRegistration GetSimpleRegistration(Type type, string? name)
{
var key = new HashKey(type, name);
@ -73,10 +73,10 @@ namespace Unity
if (candidate.Key != key) continue;
// Found a registration
if (!(candidate.Policies is ImplicitRegistration))
if (!(candidate.Policies is IRegistration))
candidate.Policies = container.CreateRegistration(type, name, candidate.Policies);
return (ImplicitRegistration)candidate.Policies;
return (IRegistration)candidate.Policies;
}
}
@ -87,9 +87,9 @@ namespace Unity
#if NETSTANDARD1_0 || NETCOREAPP1_0
private ImplicitRegistration GetGenericRegistration(Type type, string? name, TypeInfo info)
private IRegistration GetGenericRegistration(Type type, string? name, TypeInfo info)
#else
private ImplicitRegistration GetGenericRegistration(Type type, string? name)
private IRegistration GetGenericRegistration(Type type, string? name)
#endif
{
bool initGenerics = true;
@ -116,10 +116,10 @@ namespace Unity
if (candidate.Key != keyExact) continue;
// Found a registration
if (!(candidate.Policies is ImplicitRegistration))
if (!(candidate.Policies is IRegistration))
candidate.Policies = container.CreateRegistration(type, name, candidate.Policies);
return (ImplicitRegistration)candidate.Policies;
return (IRegistration)candidate.Policies;
}
// Generic registrations
@ -296,7 +296,7 @@ namespace Unity
throw new NotImplementedException();
}
private ImplicitRegistration GetOrAdd(ref HashKey key, Type type, string? name, IPolicySet? factory = null)
private IRegistration GetOrAdd(ref HashKey key, Type type, string? name, IPolicySet? factory = null)
{
Debug.Assert(null != _registry);
@ -315,10 +315,10 @@ namespace Unity
continue;
}
if (!(candidate.Policies is ImplicitRegistration))
if (!(candidate.Policies is IRegistration))
candidate.Policies = CreateRegistration(type, name, candidate.Policies);
return (ImplicitRegistration)candidate.Policies;
return (IRegistration)candidate.Policies;
}
// Expand if required
@ -330,7 +330,6 @@ namespace Unity
// Add registration
var registration = CreateRegistration(type, name, factory);
registration.AddRef();
ref var entry = ref _registry.Entries[_registry.Count];
entry.Key = key;
entry.Type = type;
@ -338,7 +337,7 @@ namespace Unity
entry.Policies = registration;
_registry.Buckets[targetBucket] = _registry.Count++;
return (ImplicitRegistration)entry.Policies;
return (IRegistration)entry.Policies;
}
}
@ -347,7 +346,7 @@ namespace Unity
#region Creating Implicit Registration
private ImplicitRegistration CreateRegistration(Type type, string? name, IPolicySet? set)
private IRegistration CreateRegistration(Type type, string? name, IPolicySet? set)
{
var registration = set is ImplicitRegistration factory
? new ImplicitRegistration(this, name, factory)

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

@ -8,7 +8,6 @@ using Unity.Exceptions;
using Unity.Registration;
using Unity.Resolution;
using Unity.Storage;
using Unity.Utility;
namespace Unity
{