Fixing enumerable resolution
This commit is contained in:
Родитель
f313d19517
Коммит
95b80366a3
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче