This commit is contained in:
Eugene Sadovoi 2019-04-19 09:35:07 -04:00
Родитель f313d19517
Коммит 95b80366a3
10 изменённых файлов: 300 добавлений и 260 удалений

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

@ -1,6 +1,9 @@
using System.Reflection;
using System;
using System.Linq;
using System.Reflection;
using Unity.Builder;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;
namespace Unity.Factories
@ -11,31 +14,40 @@ namespace Unity.Factories
private static readonly MethodInfo ResolveMethod =
typeof(UnityContainer).GetTypeInfo()
.GetDeclaredMethod(nameof(UnityContainer.ResolveArray));
.GetDeclaredMethod(nameof(UnityContainer.GetArray));
#endregion
#region ResolveDelegateFactory
public static ResolveDelegateFactory Factory = (ref BuilderContext context) =>
{
var typeArgument = context.RegistrationType.GetElementType();
var targetType = ((UnityContainer)context.Container).GetTargetType(typeArgument);
return (ResolveDelegate<BuilderContext>)
// Simple types
var method = (ResolveArray)
ResolveMethod.MakeGenericMethod(typeArgument)
.CreateDelegate(typeof(ResolveDelegate<BuilderContext>));
.CreateDelegate(typeof(ResolveArray));
return (ref BuilderContext c) => method(c.Resolve, c.Resolve);
};
#endregion
#region Resolver
#region Implementation
public static ResolveDelegate<BuilderContext> Resolver = (ref BuilderContext context) =>
{
return null;
};
#endregion
#region Nested Types
internal delegate object ResolveArray(Func<Type, string, object> resolve, Func<Type, string, InternalRegistration, object> resolveRegistration);
#endregion
}

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

@ -3,7 +3,7 @@ using System.Linq;
using System.Reflection;
using Unity.Builder;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;
namespace Unity.Factories
{
@ -12,12 +12,12 @@ namespace Unity.Factories
#region Fields
private static readonly MethodInfo EnumerableMethod =
typeof(UnityContainer).GetTypeInfo()
.GetDeclaredMethod(nameof(UnityContainer.ResolveEnumerable));
typeof(EnumerableResolver).GetTypeInfo()
.GetDeclaredMethod(nameof(EnumerableResolver.ResolveEnumerable));
private static readonly MethodInfo GenericEnumerable =
typeof(UnityContainer).GetTypeInfo()
.GetDeclaredMethod(nameof(UnityContainer.ResolveGenericEnumerable));
typeof(EnumerableResolver).GetTypeInfo()
.GetDeclaredMethod(nameof(EnumerableResolver.ResolveGeneric));
#endregion
@ -26,7 +26,6 @@ namespace Unity.Factories
public static ResolveDelegateFactory Factory = (ref BuilderContext context) =>
{
Delegate method;
#if NETSTANDARD1_0 || NETCOREAPP1_0 || NET40
var typeArgument = context.Type.GetTypeInfo().GenericTypeArguments.First();
@ -36,47 +35,47 @@ namespace Unity.Factories
if (typeArgument.IsGenericType)
#endif
{
// Generic closures
method = GenericEnumerable.MakeGenericMethod(typeArgument)
.CreateDelegate(typeof(ResolveGenericEnumerableDelegate));
var method = (ResolveEnumerableDelegate)
GenericEnumerable.MakeGenericMethod(typeArgument)
.CreateDelegate(typeof(ResolveEnumerableDelegate));
Type definition = typeArgument.GetGenericTypeDefinition();
int hashCode = typeArgument.GetHashCode() & UnityContainer.HashMask;
int hashGeneric = definition.GetHashCode() & UnityContainer.HashMask;
Type type = typeArgument.GetGenericTypeDefinition();
return (ref BuilderContext c) =>
{
return ((ResolveGenericEnumerableDelegate)method)(c.Resolve, c.Resolve, hashCode, hashGeneric, definition, c.Name, (UnityContainer)c.Container);
};
return (ref BuilderContext c) => method(ref c, type);
}
else
{
// Closures
method = EnumerableMethod.MakeGenericMethod(typeArgument)
.CreateDelegate(typeof(ResolveEnumerableDelegate));
int hashCode = typeArgument.GetHashCode() & UnityContainer.HashMask;
return (ref BuilderContext c) =>
{
return ((ResolveEnumerableDelegate)method)(c.Resolve, c.Resolve, hashCode, c.Name, (UnityContainer)c.Container);
};
return (ResolveDelegate<BuilderContext>)EnumerableMethod.MakeGenericMethod(typeArgument)
.CreateDelegate(typeof(ResolveDelegate<BuilderContext>));
}
};
#endregion
#region Implementation
private static object ResolveEnumerable<TElement>(ref BuilderContext context)
{
return ((UnityContainer)context.Container).ResolveEnumerable<TElement>(context.Resolve,
context.Resolve,
context.Name);
}
private static object ResolveGeneric<TElement>(ref BuilderContext context, Type type)
{
return ((UnityContainer)context.Container).ResolveEnumerable<TElement>(context.Resolve,
context.Resolve,
type, context.Name);
}
#endregion
#region Nested Types
private delegate object ResolveEnumerableDelegate(Func<Type, string, object> resolve,
Func<Type, string, InternalRegistration, object> resolveRegistration,
int hashCode, string name, UnityContainer unity);
private delegate object ResolveEnumerableDelegate(ref BuilderContext context, Type type);
private delegate object ResolveGenericEnumerableDelegate(Func<Type, string, object> resolve,
Func<Type, string, InternalRegistration, object> resolveRegistration,
int hashCode, int hashGeneric, Type typeDefinition,
string name, UnityContainer unity);
#endregion
}
}

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

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Security;
using System.Text;
using Unity.Resolution;
namespace Unity.Storage
{
@ -87,6 +88,29 @@ namespace Unity.Storage
return true;
}
// TODO: Redo the verification
public bool Add(Type type, string name)
{
var hashCode = NamedType.GetHashCode(type, name) & UnityContainer.HashMask;
var targetBucket = hashCode % Buckets.Length;
for (var i = Buckets[targetBucket]; i >= 0; i = Entries[i].Next)
{
if (Entries[i].Type != type) continue;
return false;
}
// Create new metadata entry
ref var entry = ref Entries[Count];
entry.Next = Buckets[targetBucket];
entry.HashCode = hashCode;
entry.Type = type;
Buckets[targetBucket] = Count++;
return true;
}
public bool RequireToGrow => (Entries.Length - Count) < 100 &&
(float)Count / Entries.Length > 0.72f;
#endregion

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

@ -1,95 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
using Unity.Builder;
using Unity.Injection;
using Unity.Policy;
using Unity.Registration;
using Unity.Resolution;
namespace Unity.Strategies
{
/// <summary>
/// This strategy is responsible for building Array
/// </summary>
public class ArrayResolveStrategy : BuilderStrategy
{
#region Fields
private readonly MethodInfo _resolveMethod;
private readonly MethodInfo _resolveGenericMethod;
#endregion
#region Constructors
public ArrayResolveStrategy(MethodInfo method, MethodInfo generic)
{
_resolveMethod = method;
_resolveGenericMethod = generic;
}
#endregion
#region Registration and Analysis
public override bool RequiredToBuildType(IUnityContainer container, Type type, InternalRegistration registration, params InjectionMember[] injectionMembers)
{
if (registration is ContainerRegistration containerRegistration)
{
if (type != containerRegistration.Type ||
#pragma warning disable CS0618 // TODO: InjectionFactory
null != injectionMembers && injectionMembers.Any(i => i is InjectionFactory))
#pragma warning restore CS0618
return false;
}
return null != type && type.IsArray && type.GetArrayRank() == 1;
}
#endregion
#region Build
public override void PreBuildUp(ref BuilderContext context)
{
var plan = context.Registration.Get<ResolveDelegate<BuilderContext>>();
if (plan == null)
{
var typeArgument = context.RegistrationType.GetElementType();
var type = ((UnityContainer)context.Container).GetFinalType(typeArgument);
if (type != typeArgument)
{
var method = (ResolveArrayDelegate)_resolveGenericMethod
.MakeGenericMethod(typeArgument)
.CreateDelegate(typeof(ResolveArrayDelegate));
plan = (ref BuilderContext c) => method(ref c, type);
}
else
{
plan = (ResolveDelegate<BuilderContext>)_resolveMethod
.MakeGenericMethod(typeArgument)
.CreateDelegate(typeof(ResolveDelegate<BuilderContext>));
}
context.Registration.Set(typeof(ResolveDelegate<BuilderContext>), plan);
}
context.Existing = plan(ref context);
context.BuildComplete = true;
}
#endregion
#region Nested Types
private delegate object ResolveArrayDelegate(ref BuilderContext context, Type type);
#endregion
}
}

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

@ -76,7 +76,7 @@ namespace Unity.Strategies
if (null != map) context.Type = map(context.Type);
if (!((InternalRegistration)context.Registration).BuildRequired &&
((UnityContainer)context.Container).RegistrationExists(ref context))
((UnityContainer)context.Container).IsRegistered(ref context))
{
// TODO: Optimize call, no need for parameters
context.Existing = context.Resolve(context.Type, context.Name);

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

@ -49,7 +49,6 @@ namespace Unity
// Methods
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private Func<Type, string, IPolicySet> _get;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private Func<Type, string, Type, IPolicySet> _getGenericRegistration;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] internal Func<Type, bool> IsTypeExplicitlyRegistered;
#endregion
@ -244,7 +243,6 @@ namespace Unity
_get = (type, name) => Get(type, name) ?? _parent._get(type, name);
_getGenericRegistration = GetOrAddGeneric;
IsTypeExplicitlyRegistered = IsTypeTypeExplicitlyRegisteredLocally;
}
}
@ -267,36 +265,6 @@ namespace Unity
.ToArray();
}
internal Type GetFinalType(Type argType)
{
Type next;
for (var type = argType; null != type; type = next)
{
var info = type.GetTypeInfo();
if (info.IsGenericType)
{
if (IsTypeExplicitlyRegistered(type)) return type;
var definition = info.GetGenericTypeDefinition();
if (IsTypeExplicitlyRegistered(definition)) return definition;
next = info.GenericTypeArguments[0];
if (IsTypeExplicitlyRegistered(next)) return next;
}
else if (type.IsArray)
{
next = type.GetElementType();
if (IsTypeExplicitlyRegistered(next)) return next;
}
else
{
return type;
}
}
return argType;
}
#endregion

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

@ -43,7 +43,6 @@ namespace Unity
// Methods
_get = Get;
_getGenericRegistration = GetOrAddGeneric;
IsTypeExplicitlyRegistered = IsTypeTypeExplicitlyRegisteredLocally;
// Build Strategies
_strategies = new StagedStrategyChain<BuilderStrategy, UnityBuildStage>

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

@ -43,31 +43,24 @@ namespace Unity
#region Check Registration
private bool IsTypeTypeExplicitlyRegisteredLocally(Type type)
internal bool IsRegistered(Type type)
{
var hashCode = (type?.GetHashCode() ?? 0) & 0x7FFFFFFF;
var targetBucket = hashCode % _registrations.Buckets.Length;
for (var i = _registrations.Buckets[targetBucket]; i >= 0; i = _registrations.Entries[i].Next)
{
ref var candidate = ref _registrations.Entries[i];
if (candidate.HashCode != hashCode ||
candidate.Key != type)
{
continue;
}
var hashCode = type?.GetHashCode() ?? 0 & UnityContainer.HashMask;
return candidate.Value
.Values
.Any(v => v is ContainerRegistration) ||
(_parent?.IsTypeExplicitlyRegistered(type) ?? false);
// Iterate through containers hierarchy
for (var container = this; null != container; container = container._parent)
{
// Skip to parent if no registrations
if (null == container._metadata) continue;
if (container._metadata.Contains(hashCode, type)) return true;
}
return _parent?.IsTypeExplicitlyRegistered(type) ?? false;
return false;
}
internal bool RegistrationExists(ref BuilderContext context)
internal bool IsRegistered(ref BuilderContext context)
{
Type generic = null;
int targetBucket, hashGeneric = -1, hashDefault = -1;
int hashExact = NamedType.GetHashCode(context.Type, context.Name) & 0x7FFFFFFF;

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

@ -340,14 +340,12 @@ namespace Unity
#endif
public static bool Contains(this Registry<NamedType, InternalRegistration> registry, Type type, string name)
{
var hashCode = NamedType.GetHashCode(type, name);
var hashCode = NamedType.GetHashCode(type, name) & UnityContainer.HashMask;
var targetBucket = hashCode % registry.Buckets.Length;
for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next)
{
ref var entry = ref registry.Entries[i];
if (entry.Key.Type != type) continue;
return true;
if (registry.Entries[i].Key.Type == type) return true;
}
return false;
@ -358,14 +356,12 @@ namespace Unity
#endif
public static bool Contains(this Registry<NamedType, InternalRegistration> registry, ref NamedType key)
{
var hashCode = key.GetHashCode();
var hashCode = key.GetHashCode() & UnityContainer.HashMask;
var targetBucket = hashCode % registry.Buckets.Length;
for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next)
{
ref var entry = ref registry.Entries[i];
if (entry.Key.Type != key.Type) continue;
return true;
if (registry.Entries[i].Key.Type == key.Type) return true;
}
return false;
@ -380,9 +376,7 @@ namespace Unity
for (var i = registry.Buckets[targetBucket]; i >= 0; i = registry.Entries[i].Next)
{
ref var entry = ref registry.Entries[i];
if (entry.Key.Type != type) continue;
return true;
if (registry.Entries[i].Key.Type == type) return true;
}
return false;
@ -449,6 +443,21 @@ namespace Unity
}
}
#if !NET40
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public static bool Contains(this Registry<Type, int[]> metadata, int hashCode, Type type)
{
var targetBucket = hashCode % metadata.Buckets.Length;
for (var i = metadata.Buckets[targetBucket]; i >= 0; i = metadata.Entries[i].Next)
{
if (metadata.Entries[i].Key == type) return true;
}
return false;
}
#endregion
}

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

@ -88,15 +88,16 @@ namespace Unity
#region Resolving Enumerable
internal static IEnumerable<TElement> ResolveEnumerable<TElement>(Func<Type, string, object> resolve,
Func<Type, string, InternalRegistration, object> resolveRegistration,
int hashCode, string name, UnityContainer unity)
internal IEnumerable<TElement> ResolveEnumerable<TElement>(Func<Type, string, object> resolve,
Func<Type, string, InternalRegistration, object> resolveRegistration,
string name)
{
TElement value;
var set = new QuickSet();
int hashCode = typeof(TElement).GetHashCode() & HashMask;
// Iterate over hierarchy
for (var container = unity; null != container; container = container._parent)
for (var container = this; null != container; container = container._parent)
{
// Skip to parent if no data
if (null == container._metadata) continue;
@ -144,16 +145,17 @@ namespace Unity
}
}
internal static IEnumerable<TElement> ResolveGenericEnumerable<TElement>(Func<Type, string, object> resolve,
Func<Type, string, InternalRegistration, object> resolveRegistration,
int hashCode, int hashGeneric, Type typeDefinition,
string name, UnityContainer unity)
internal IEnumerable<TElement> ResolveEnumerable<TElement>(Func<Type, string, object> resolve,
Func<Type, string, InternalRegistration, object> resolveRegistration,
Type typeDefinition, string name)
{
TElement value;
var set = new QuickSet();
int hashCode = typeof(TElement).GetHashCode() & HashMask;
int hashGeneric = typeDefinition.GetHashCode() & HashMask;
// Iterate over hierarchy
for (var container = unity; null != container; container = container._parent)
for (var container = this; null != container; container = container._parent)
{
// Skip to parent if no data
if (null == container._metadata) continue;
@ -194,15 +196,20 @@ namespace Unity
if (set.RequireToGrow) set = new QuickSet(set);
if (set.Add(registry.Entries[index].HashCode, registry.Entries[index].Key.Type))
{
try
{
value = (TElement)resolve(typeof(TElement), registry.Entries[index].Key.Name);
}
catch (ArgumentException ex) when (ex.InnerException is TypeLoadException)
catch (MakeGenericTypeFailedException) { continue; }
catch (InvalidOperationException ex) when (ex.InnerException is InvalidRegistrationException)
{
continue;
}
// TODO: Verify if required
//catch (ArgumentException ex) when (ex.InnerException is TypeLoadException)
//{
// continue;
//}
yield return value;
}
@ -230,74 +237,198 @@ namespace Unity
#region Resolving Array
internal static object ResolveArray<TElement>(ref BuilderContext context)
internal Type GetTargetType(Type argType)
{
var type = typeof(TElement);
#if NETSTANDARD1_0 || NETCOREAPP1_0
var generic = type.GetTypeInfo().IsGenericType ? type.GetGenericTypeDefinition() : type;
#else
var generic = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
#endif
var set = generic == type ? NamedRegistrations((UnityContainer)context.Container, type)
: NamedRegistrations((UnityContainer)context.Container, type, generic);
Type next;
for (var type = argType; null != type; type = next)
{
var info = type.GetTypeInfo();
if (info.IsGenericType)
{
if (IsRegistered(type)) return type;
return ArrayResolver<TElement>(context.Resolve, context.Resolve, context.Name, set).ToArray();
var definition = info.GetGenericTypeDefinition();
if (IsRegistered(definition)) return definition;
next = info.GenericTypeArguments[0];
if (IsRegistered(next)) return next;
}
else if (type.IsArray)
{
next = type.GetElementType();
if (IsRegistered(next)) return next;
}
else
{
return type;
}
}
return argType;
}
private static IEnumerable<TElement> ArrayResolver<TElement>(Func<Type, string, object> resolve,
Func<Type, string, InternalRegistration, object> resolveReg,
string name,
RegistrationSet registrations)
internal IEnumerable<TElement> ResolveArray<TElement>(Func<Type, string, object> resolve,
Func<Type, string, InternalRegistration, object> resolveRegistration)
{
var type = typeof(TElement);
TElement value;
var set = new QuickSet();
int hashCode = typeof(TElement).GetHashCode() & HashMask;
for (var i = 0; i < registrations.Count; i++)
// Iterate over hierarchy
for (var container = this; null != container; container = container._parent)
{
try
{
#if NETSTANDARD1_0 || NETCOREAPP1_0
if (registrations[i].RegisteredType.GetTypeInfo().IsGenericTypeDefinition)
#else
if (registrations[i].RegisteredType.IsGenericTypeDefinition)
#endif
value = (TElement)resolve(type, registrations[i].Name);
else
value = (TElement)resolveReg(type, registrations[i].Name, registrations[i].Registration);
}
catch (ArgumentException ex) when (ex.InnerException is TypeLoadException)
{
continue;
}
// Skip to parent if no data
if (null == container._metadata) continue;
yield return value;
// Hold on to registries
var registry = container._registry;
var metadata = container._metadata;
// Get indexes and iterate over them
var length = metadata.GetEntries<TElement>(hashCode, out int[] data);
for (var i = 1; i < length; i++)
{
var index = data[i];
if (set.RequireToGrow) set = new QuickSet(set);
if (set.Add(registry.Entries[index].HashCode, registry.Entries[index].Key.Type))
{
try
{
value = (TElement)resolveRegistration(typeof(TElement), registry.Entries[index].Key.Name, registry.Entries[index].Value);
}
catch (ArgumentException ex) when (ex.InnerException is TypeLoadException)
{
continue;
}
yield return value;
}
}
}
}
internal static object ResolveGenericArray<TElement>(ref BuilderContext context, Type type)
internal IEnumerable<TElement> GetArray<TElement>(Func<Type, string, InternalRegistration, object> resolve)
{
var set = NamedRegistrations((UnityContainer)context.Container, typeof(TElement), type);
return ResolveGenericRegistrations<TElement>(ref context, set).ToArray();
}
TElement value;
var set = new HashSet<string>();
int hashCode = typeof(TElement).GetHashCode() & HashMask;
private static IList<TElement> ResolveGenericRegistrations<TElement>(ref BuilderContext context, RegistrationSet registrations)
{
var list = new List<TElement>();
for (var i = 0; i < registrations.Count; i++)
// Iterate over hierarchy
for (var container = this; null != container; container = container._parent)
{
ref var entry = ref registrations[i];
try
// Skip to parent if no data
if (null == container._metadata) continue;
// Hold on to registries
var registry = container._registry;
var metadata = container._metadata;
// Get indexes and iterate over them
var length = metadata.GetEntries<TElement>(hashCode, out int[] data);
for (var i = 1; i < length; i++)
{
list.Add((TElement)context.Resolve(typeof(TElement), entry.Name));
}
catch (MakeGenericTypeFailedException) { /* Ignore */ }
catch (InvalidOperationException ex) when (ex.InnerException is InvalidRegistrationException)
{
// Ignore
var index = data[i];
var name = registry.Entries[index].Key.Name;
if (null == name) continue;
if (set.Add(name))
{
try
{
value = (TElement)resolve(typeof(TElement), name, registry.Entries[index].Value);
}
catch (ArgumentException ex) when (ex.InnerException is TypeLoadException)
{
continue;
}
yield return value;
}
}
}
}
return list;
internal IEnumerable<TElement> ResolveArrayTarget<TElement, TTarget>(Func<Type, string, object> resolve)
{
TElement value;
var set = new HashSet<string>();
int hashCode = typeof(TTarget).GetHashCode() & HashMask;
// Iterate over hierarchy
for (var container = this; null != container; container = container._parent)
{
// Skip to parent if no data
if (null == container._metadata) continue;
// Hold on to registries
var registry = container._registry;
var metadata = container._metadata;
// Get indexes and iterate over them
var length = metadata.GetEntries<TTarget>(hashCode, out int[] data);
for (var i = 1; i < length; i++)
{
var index = data[i];
var name = registry.Entries[index].Key.Name;
if (null == name) continue;
if (set.Add(name))
{
try
{
value = (TElement)resolve(typeof(TElement), name);
}
catch (ArgumentException ex) when (ex.InnerException is TypeLoadException)
{
continue;
}
yield return value;
}
}
}
}
internal IEnumerable<TElement> DefinitionArray<TElement>(Func<Type, string, InternalRegistration, object> resolve, Type type)
{
TElement value;
var set = new HashSet<string>();
int hashCode = typeof(TElement).GetHashCode() & HashMask;
// Iterate over hierarchy
for (var container = this; null != container; container = container._parent)
{
// Skip to parent if no data
if (null == container._metadata) continue;
// Hold on to registries
var registry = container._registry;
var metadata = container._metadata;
// Get indexes and iterate over them
var length = metadata.GetEntries<TElement>(hashCode, out int[] data);
for (var i = 1; i < length; i++)
{
var index = data[i];
var name = registry.Entries[index].Key.Name;
if (null == name) continue;
if (set.Add(name))
{
try
{
value = (TElement)resolve(typeof(TElement), name, registry.Entries[index].Value);
}
catch (ArgumentException ex) when (ex.InnerException is TypeLoadException)
{
continue;
}
yield return value;
}
}
}
}
#endregion