Skip to content

Commit 34db976

Browse files
committed
1 parent 9fc07e5 commit 34db976

File tree

7 files changed

+334
-696
lines changed

7 files changed

+334
-696
lines changed

src/Strategies/ArrayResolveStrategy.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Linq;
23
using System.Reflection;
34
using Unity.Builder;
45
using Unity.Builder.Strategy;
@@ -16,17 +17,18 @@ public class ArrayResolveStrategy : BuilderStrategy
1617
#region Fields
1718

1819
private readonly MethodInfo _resolveMethod;
19-
private readonly MethodInfo _resolveLazyMethod;
20+
private readonly MethodInfo _resolveGenericMethod;
21+
delegate void ResolveGenericArray(IBuilderContext context, Type type);
2022

2123
#endregion
2224

2325

2426
#region Constructors
2527

26-
public ArrayResolveStrategy(MethodInfo method, MethodInfo lazy)
28+
public ArrayResolveStrategy(MethodInfo method, MethodInfo generic)
2729
{
2830
_resolveMethod = method;
29-
_resolveLazyMethod = lazy;
31+
_resolveGenericMethod = generic;
3032
}
3133

3234
#endregion
@@ -39,14 +41,24 @@ public override void PreBuildUp(IBuilderContext context)
3941
var plan = context.Registration.Get<IBuildPlanPolicy>();
4042
if (plan == null)
4143
{
42-
var type = context.OriginalBuildKey.Type.GetElementType();
43-
var info = type.GetTypeInfo();
44-
var buildMethod = info.IsGenericType && typeof(Lazy<>) == info.GetGenericTypeDefinition()
45-
? _resolveLazyMethod.MakeGenericMethod(type).CreateDelegate(typeof(DynamicBuildPlanMethod))
46-
: _resolveMethod.MakeGenericMethod(type).CreateDelegate(typeof(DynamicBuildPlanMethod));
44+
var typeArgument = context.OriginalBuildKey.Type.GetElementType();
45+
var type = ((UnityContainer)context.Container).GetFinalType(typeArgument);
46+
if (type != typeArgument)
47+
{
48+
var method = _resolveGenericMethod.MakeGenericMethod(typeArgument)
49+
.CreateDelegate(typeof(ResolveGenericArray));
50+
51+
plan = new DynamicMethodBuildPlan(c => method.DynamicInvoke(c, type));
52+
}
53+
else
54+
{
55+
plan = new DynamicMethodBuildPlan((DynamicBuildPlanMethod)
56+
_resolveMethod.MakeGenericMethod(typeArgument)
57+
.CreateDelegate(typeof(DynamicBuildPlanMethod)));
58+
}
4759

48-
plan = new DynamicMethodBuildPlan((DynamicBuildPlanMethod)buildMethod);
4960
context.Registration.Set(typeof(IBuildPlanPolicy), plan);
61+
5062
}
5163

5264
plan?.BuildUp(context);

src/Strategies/EnumerableResolveStrategy.cs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,25 @@
1111
namespace Unity.Strategies
1212
{
1313
/// <summary>
14-
/// This strategy is responsible for building IEnumerable<>
14+
/// This strategy is responsible for building IEnumerable
1515
/// </summary>
1616
public class EnumerableResolveStrategy : BuilderStrategy
1717
{
1818
#region Fields
1919

2020
private readonly MethodInfo _resolveMethod;
21-
private readonly MethodInfo _resolveLazyMethod;
21+
private readonly MethodInfo _resolveGenericMethod;
22+
delegate void ResolveGenericEnumerable(IBuilderContext context, Type type);
2223

2324
#endregion
2425

2526

2627
#region Constructors
2728

28-
public EnumerableResolveStrategy(MethodInfo method, MethodInfo lazy)
29+
public EnumerableResolveStrategy(MethodInfo method, MethodInfo generic)
2930
{
3031
_resolveMethod = method;
31-
_resolveLazyMethod = lazy;
32+
_resolveGenericMethod = generic;
3233
}
3334

3435
#endregion
@@ -41,17 +42,26 @@ public override void PreBuildUp(IBuilderContext context)
4142
var plan = context.Registration.Get<IBuildPlanPolicy>();
4243
if (plan == null)
4344
{
44-
var args = context.BuildKey.Type.GetTypeInfo().GenericTypeArguments.First();
45-
var info = args.GetTypeInfo();
46-
var buildMethod = info.IsGenericType && typeof(Lazy<>) == info.GetGenericTypeDefinition()
47-
? _resolveLazyMethod.MakeGenericMethod(args).CreateDelegate(typeof(DynamicBuildPlanMethod))
48-
: _resolveMethod.MakeGenericMethod(args).CreateDelegate(typeof(DynamicBuildPlanMethod));
45+
var typeArgument = context.BuildKey.Type.GetTypeInfo().GenericTypeArguments.First();
46+
var type = ((UnityContainer) context.Container).GetFinalType(typeArgument);
47+
if (type != typeArgument)
48+
{
49+
var method = _resolveGenericMethod.MakeGenericMethod(typeArgument)
50+
.CreateDelegate(typeof(ResolveGenericEnumerable));
51+
52+
plan = new DynamicMethodBuildPlan(c => method.DynamicInvoke(c, type));
53+
}
54+
else
55+
{
56+
plan = new DynamicMethodBuildPlan((DynamicBuildPlanMethod)
57+
_resolveMethod.MakeGenericMethod(typeArgument)
58+
.CreateDelegate(typeof(DynamicBuildPlanMethod)));
59+
}
4960

50-
plan = new DynamicMethodBuildPlan((DynamicBuildPlanMethod)buildMethod);
5161
context.Registration.Set(typeof(IBuildPlanPolicy), plan);
5262
}
5363

54-
plan?.BuildUp(context);
64+
plan.BuildUp(context);
5565
context.BuildComplete = true;
5666
}
5767

@@ -64,8 +74,7 @@ public override bool RequiredToBuildType(IUnityContainer container, INamedType n
6474
{
6575
return namedType is InternalRegistration registration &&
6676
registration.Type.GetTypeInfo().IsGenericType &&
67-
typeof(IEnumerable<>) == registration.Type.GetGenericTypeDefinition()
68-
? true : false;
77+
typeof(IEnumerable<>) == registration.Type.GetGenericTypeDefinition();
6978
}
7079

7180
#endregion

src/UnityContainer.Implementation.cs

Lines changed: 112 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ public partial class UnityContainer
7575
internal SetPolicyDelegate SetPolicy;
7676
internal ClearPolicyDelegate ClearPolicy;
7777

78+
private Func<Type, string, IPolicySet> _get;
79+
private Func<Type, string, Type, IPolicySet> _getGenericRegistration;
80+
7881
#endregion
7982

8083

@@ -107,15 +110,19 @@ public UnityContainer()
107110
SetPolicy = Set;
108111
ClearPolicy = Clear;
109112

113+
_get = Get;
114+
_getGenericRegistration = GetOrAddGeneric;
115+
116+
110117
// TODO: Initialize disposables
111118
_lifetimeContainer.Add(_strategies);
112119
_lifetimeContainer.Add(_buildPlanStrategies);
113120

114121
// Main strategy chain
115-
_strategies.Add(new ArrayResolveStrategy(typeof(UnityContainer).GetTypeInfo().GetDeclaredMethod(nameof(ResolveArray)),
116-
typeof(UnityContainer).GetTypeInfo().GetDeclaredMethod(nameof(ResolveLazyArray))), UnityBuildStage.Enumerable);
117-
_strategies.Add(new EnumerableResolveStrategy(typeof(UnityContainer).GetTypeInfo().GetDeclaredMethod(nameof(ResolveEnumerable)),
118-
typeof(UnityContainer).GetTypeInfo().GetDeclaredMethod(nameof(ResolveLazyEnumerable))), UnityBuildStage.Enumerable);
122+
_strategies.Add(new ArrayResolveStrategy(typeof(UnityContainer).GetTypeInfo().GetDeclaredMethod(nameof(ResolveArray)),
123+
typeof(UnityContainer).GetTypeInfo().GetDeclaredMethod(nameof(ResolveGenericArray))), UnityBuildStage.Enumerable);
124+
_strategies.Add(new EnumerableResolveStrategy(typeof(UnityContainer).GetTypeInfo().GetDeclaredMethod(nameof(ResolveEnumerable)),
125+
typeof(UnityContainer).GetTypeInfo().GetDeclaredMethod(nameof(ResolveGenericEnumerable))), UnityBuildStage.Enumerable);
119126
_strategies.Add(new BuildKeyMappingStrategy(), UnityBuildStage.TypeMapping);
120127
_strategies.Add(new LifetimeStrategy(), UnityBuildStage.Lifetime);
121128
_strategies.Add(new BuildPlanStrategy(), UnityBuildStage.Creation);
@@ -131,7 +138,7 @@ public UnityContainer()
131138
_strategies.Invalidated += OnStrategiesChanged;
132139

133140
// Default Policies
134-
Set( null, null, GetDefaultPolicies());
141+
Set(null, null, GetDefaultPolicies());
135142
Set(typeof(Func<>), string.Empty, typeof(ILifetimePolicy), new PerResolveLifetimeManager());
136143
Set(typeof(Func<>), string.Empty, typeof(IBuildPlanPolicy), new DeferredResolveCreatorPolicy());
137144
Set(typeof(Lazy<>), string.Empty, typeof(IBuildPlanCreatorPolicy), new GenericLazyBuildPlanCreatorPolicy());
@@ -167,6 +174,9 @@ private UnityContainer(UnityContainer parent)
167174
SetPolicy = CreateAndSetPolicy;
168175
ClearPolicy = delegate { };
169176

177+
_get = _parent._get;
178+
_getGenericRegistration = _parent._getGenericRegistration;
179+
170180
// Strategies
171181
_strategies = _parent._strategies;
172182
_buildPlanStrategies = _parent._buildPlanStrategies;
@@ -225,11 +235,27 @@ private void SetupChildContainerBehaviors()
225235
{
226236
_registrations = new HashRegistry<Type, IRegistry<string, IPolicySet>>(ContainerInitialCapacity);
227237
IsTypeRegistered = IsTypeRegisteredLocally;
228-
GetRegistration = (type, name) => Get(type, name) ?? _parent.GetRegistration(type, name);
229238
Register = AddOrUpdate;
230239
GetPolicy = Get;
231240
SetPolicy = Set;
232241
ClearPolicy = Clear;
242+
243+
GetRegistration = GetDynamicRegistration;
244+
245+
_get = GetChained;
246+
_getGenericRegistration = GetOrAddGeneric;
247+
}
248+
249+
250+
private IPolicySet GetDynamicRegistration(Type type, string name)
251+
{
252+
var registration = _get(type, name);
253+
if (null != registration) return registration;
254+
255+
var info = type.GetTypeInfo();
256+
return !info.IsGenericType
257+
? _root.GetOrAdd(type, name)
258+
: GetOrAddGeneric(type, name, info.GetGenericTypeDefinition());
233259
}
234260

235261
private static object ThrowingBuildUp(IBuilderContext context)
@@ -362,19 +388,36 @@ private static MiniHashSet<InternalRegistration> GetNamedRegistrations(UnityCont
362388
return set;
363389
}
364390

365-
private static MiniHashSet<InternalRegistration> GetNotEmptyRegistrations(UnityContainer container, Type type)
391+
private static void GetNamedRegistrations(UnityContainer container, Type type, MiniHashSet<InternalRegistration> set)
366392
{
367-
MiniHashSet<InternalRegistration> set;
368-
369393
if (null != container._parent)
370-
set = GetNotEmptyRegistrations(container._parent, type);
371-
else
372-
set = new MiniHashSet<InternalRegistration>();
394+
GetNamedRegistrations(container._parent, type, set);
395+
396+
if (null == container._registrations) return;
397+
398+
var registrations = container.Get(type);
399+
if (registrations?.Values != null)
400+
{
401+
var registry = registrations.Values;
402+
foreach (var entry in registry)
403+
{
404+
if (entry is IContainerRegistration registration &&
405+
!string.IsNullOrEmpty(registration.Name))
406+
set.Add((InternalRegistration)registration);
407+
}
408+
}
409+
}
410+
411+
private static MiniHashSet<InternalRegistration> GetExplicitRegistrations(UnityContainer container, Type type)
412+
{
413+
var set = null != container._parent
414+
? GetExplicitRegistrations(container._parent, type)
415+
: new MiniHashSet<InternalRegistration>();
373416

374417
if (null == container._registrations) return set;
375418

376419
var registrations = container.Get(type);
377-
if (null != registrations && null != registrations.Values)
420+
if (registrations?.Values != null)
378421
{
379422
var registry = registrations.Values;
380423
foreach (var entry in registry)
@@ -389,7 +432,7 @@ private static MiniHashSet<InternalRegistration> GetNotEmptyRegistrations(UnityC
389432
if (generic != type)
390433
{
391434
registrations = container.Get(generic);
392-
if (null != registrations && null != registrations.Values)
435+
if (registrations?.Values != null)
393436
{
394437
var registry = registrations.Values;
395438
foreach (var entry in registry)
@@ -402,8 +445,29 @@ private static MiniHashSet<InternalRegistration> GetNotEmptyRegistrations(UnityC
402445

403446
return set;
404447
}
405-
406-
internal IList<BuilderStrategy> GetBuilders(InternalRegistration registration)
448+
449+
private static void GetExplicitRegistrations(UnityContainer container, Type type, MiniHashSet<InternalRegistration> set)
450+
{
451+
if (null != container._parent)
452+
GetExplicitRegistrations(container._parent, type, set);
453+
454+
if (null == container._registrations) return;
455+
456+
var registrations = container.Get(type);
457+
if (registrations?.Values != null)
458+
{
459+
var registry = registrations.Values;
460+
foreach (var entry in registry)
461+
{
462+
if (entry is IContainerRegistration registration && string.Empty != registration.Name)
463+
set.Add((InternalRegistration)registration);
464+
}
465+
}
466+
467+
return;
468+
}
469+
470+
private IList<BuilderStrategy> GetBuilders(InternalRegistration registration)
407471
{
408472
var chain = new List<BuilderStrategy>();
409473
var strategies = _buildChain;
@@ -433,6 +497,38 @@ private IPolicySet CreateRegistration(Type type, string name, Type policyInterfa
433497
return registration;
434498
}
435499

500+
internal Type GetFinalType(Type argType)
501+
{
502+
Type next;
503+
for (var type = argType; null != type; type = next)
504+
{
505+
var info = type.GetTypeInfo();
506+
if (info.IsGenericType)
507+
{
508+
var definition = info.GetGenericTypeDefinition();
509+
if (typeof(Lazy<>) != definition &&
510+
typeof(Func<>) != definition &&
511+
null != GetChained(definition)) return definition;
512+
513+
next = info.GenericTypeArguments[0];
514+
if (null != GetChained(next)) return next;
515+
}
516+
else if (info.IsArray)
517+
{
518+
next = info.GetElementType();
519+
if (typeof(Lazy<>) != next &&
520+
typeof(Func<>) != next &&
521+
null != GetChained(next)) return next;
522+
}
523+
else
524+
{
525+
return type;
526+
}
527+
}
528+
529+
return argType;
530+
}
531+
436532
#endregion
437533

438534

0 commit comments

Comments
 (0)