Skip to content

Commit 52e77d2

Browse files
committed
Fixed #45
1 parent 578dd06 commit 52e77d2

File tree

10 files changed

+132
-85
lines changed

10 files changed

+132
-85
lines changed

src/ObjectBuilder/BuilderContext.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ public void AddResolverOverrides(IEnumerable<ResolverOverride> newOverrides)
221221
_ownsOverrides = true;
222222
}
223223

224-
_resolverOverrides.AddRange(newOverrides);
224+
if (null != newOverrides)
225+
_resolverOverrides.AddRange(newOverrides);
225226
}
226227

227228
/// <summary>

src/ObjectBuilder/Policies/OverriddenBuildPlanMarkerPolicy.cs

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/ObjectBuilder/Policies/ResolveBuildUpPolicy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public class ResolveBuildUpPolicy : IBuildPlanPolicy
77
{
88
public void BuildUp(IBuilderContext context)
99
{
10-
context.Existing = context.NewBuildUp(context.BuildKey);
10+
context.Existing = context.NewBuildUp(context.BuildKey.Type, context.BuildKey.Name);
1111
context.BuildComplete = null != context.Existing;
1212
}
1313
}
Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
2-
1+
using System;
2+
using System.Linq;
3+
using System.Reflection;
34
using Unity.Builder;
45
using Unity.Builder.Strategy;
6+
using Unity.Injection;
7+
using Unity.Lifetime;
8+
using Unity.ObjectBuilder.Policies;
59
using Unity.Policy;
10+
using Unity.Registration;
11+
using Unity.Strategy;
612

713
namespace Unity.ObjectBuilder.Strategies
814
{
915
/// <summary>
1016
/// Represents a strategy for mapping build keys in the build up operation.
1117
/// </summary>
12-
public class BuildKeyMappingStrategy : BuilderStrategy
18+
public class BuildKeyMappingStrategy : BuilderStrategy, IRegisterTypeStrategy
1319
{
1420
/// <summary>
1521
/// Called during the chain of responsibility for a build operation. Looks for the <see cref="IBuildKeyMappingPolicy"/>
@@ -18,11 +24,40 @@ public class BuildKeyMappingStrategy : BuilderStrategy
1824
/// <param name="context">The context for the operation.</param>
1925
public override object PreBuildUp(IBuilderContext context)
2026
{
21-
var policy = context.Policies.GetPolicy<IBuildKeyMappingPolicy>(context.BuildKey, out _);
27+
var policy = context.Policies.Get<IBuildKeyMappingPolicy>(context.BuildKey, out _);
2228
if (null == policy) return null;
2329

2430
context.BuildKey = policy.Map(context.BuildKey, context);
31+
2532
return null;
2633
}
34+
35+
public void RegisterType(IContainerContext context, Type typeFrom, Type typeTo, string name,
36+
LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
37+
{
38+
var buildType = typeFrom ?? typeTo;
39+
40+
if (null == typeFrom || typeFrom == typeTo)
41+
{
42+
context.Policies.Clear(buildType, name, typeof(IBuildKeyMappingPolicy));
43+
return;
44+
}
45+
46+
var buildKey = new NamedTypeBuildKey(buildType, name);
47+
48+
if (typeFrom.GetTypeInfo().IsGenericTypeDefinition && typeTo.GetTypeInfo().IsGenericTypeDefinition)
49+
{
50+
context.Policies.Set<IBuildKeyMappingPolicy>(new GenericTypeBuildKeyMappingPolicy(new NamedTypeBuildKey(typeTo, name)),
51+
new NamedTypeBuildKey(typeFrom, name));
52+
}
53+
else
54+
{
55+
context.Policies.Set<IBuildKeyMappingPolicy>(new BuildKeyMappingPolicy(new NamedTypeBuildKey(typeTo, name)), buildKey);
56+
}
57+
58+
var members = null == injectionMembers ? new InjectionMember[0] : injectionMembers;
59+
if (!members.Where(m => m is InjectionConstructor || m is InjectionMethod || m is InjectionProperty).Any() && !(lifetimeManager is IRequireBuildUpPolicy))
60+
context.Policies.Set<IBuildPlanPolicy>(new ResolveBuildUpPolicy(), buildKey);
61+
}
2762
}
2863
}

src/ObjectBuilder/Strategies/BuildPlanStrategy.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
2-
3-
using System;
1+
using System;
42
using Unity.Builder;
53
using Unity.Builder.Strategy;
4+
using Unity.Lifetime;
65
using Unity.ObjectBuilder.Policies;
76
using Unity.Policy;
7+
using Unity.Registration;
8+
using Unity.Strategy;
89

910
namespace Unity.ObjectBuilder.Strategies
1011
{

src/ObjectBuilder/Strategies/LifetimeStrategy.cs

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
2-
3-
using System;
1+
using System;
42
using System.Reflection;
53
using Unity.Builder;
64
using Unity.Builder.Strategy;
75
using Unity.Exceptions;
6+
using Unity.Extension;
87
using Unity.Lifetime;
98
using Unity.Policy;
9+
using Unity.Registration;
10+
using Unity.Strategy;
1011

1112
namespace Unity.ObjectBuilder.Strategies
1213
{
@@ -16,10 +17,16 @@ namespace Unity.ObjectBuilder.Strategies
1617
/// has already been created and to update or remove that
1718
/// object from some backing store.
1819
/// </summary>
19-
public class LifetimeStrategy : BuilderStrategy
20+
public class LifetimeStrategy : BuilderStrategy, IRegisterTypeStrategy
2021
{
22+
#region Fields
23+
2124
private readonly object _genericLifetimeManagerLock = new object();
22-
private static readonly TransientLifetimeManager TransientManager = new TransientLifetimeManager();
25+
26+
#endregion
27+
28+
29+
#region BuilderStrategy
2330

2431
/// <summary>
2532
/// Called during the chain of responsibility for a build operation. The
@@ -70,7 +77,7 @@ private ILifetimePolicy GetLifetimePolicy(IBuilderContext context, out IPolicyLi
7077

7178
if (policy == null)
7279
{
73-
policy = TransientManager;
80+
policy = TransientLifetimeManager.Instance;
7481
context.PersistentPolicies.Set(policy, context.OriginalBuildKey);
7582
}
7683

@@ -110,5 +117,44 @@ private ILifetimePolicy GetLifetimePolicyForGenericType(IBuilderContext context,
110117

111118
return null;
112119
}
120+
121+
#endregion
122+
123+
124+
#region IRegisterTypeStrategy
125+
126+
public void RegisterType(IContainerContext context, Type typeFrom, Type typeTo, string name,
127+
LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers)
128+
{
129+
var lifetimeType = typeFrom ?? typeTo;
130+
131+
if (null == lifetimeManager)
132+
{
133+
context.Policies.Clear(lifetimeType, name, typeof(ILifetimePolicy));
134+
return;
135+
}
136+
137+
if (lifetimeManager.InUse)
138+
{
139+
throw new InvalidOperationException(Constants.LifetimeManagerInUse);
140+
}
141+
142+
if (lifetimeType.GetTypeInfo().IsGenericTypeDefinition)
143+
{
144+
LifetimeManagerFactory factory = new LifetimeManagerFactory((ExtensionContext)context, lifetimeManager.GetType());
145+
context.Policies.Set<ILifetimeFactoryPolicy>(factory, new NamedTypeBuildKey(lifetimeType, name));
146+
}
147+
else
148+
{
149+
lifetimeManager.InUse = true;
150+
context.Policies.Set<ILifetimePolicy>(lifetimeManager, new NamedTypeBuildKey(lifetimeType, name));
151+
if (lifetimeManager is IDisposable)
152+
{
153+
context.Lifetime.Add(lifetimeManager);
154+
}
155+
}
156+
}
157+
158+
#endregion
113159
}
114160
}

src/UnityContainer.Implementation.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Globalization;
4-
using System.Linq.Expressions;
54
using System.Reflection;
65
using Unity.Builder;
76
using Unity.Builder.Strategy;
@@ -32,6 +31,7 @@ public partial class UnityContainer
3231
private readonly List<UnityContainerExtension> _extensions;
3332
private readonly StagedStrategyChain<UnityBuildStage> _strategies;
3433
private readonly StagedStrategyChain<BuilderStage> _buildPlanStrategies;
34+
private readonly ContainerContext _context;
3535

3636
private event EventHandler<RegisterEventArgs> Registering;
3737
private event EventHandler<RegisterInstanceEventArgs> RegisteringInstance;
@@ -53,7 +53,7 @@ private UnityContainer(UnityContainer parent)
5353

5454
_parent = parent;
5555
_parent?._lifetimeContainer.Add(this);
56-
56+
_context = new ContainerContext(this);
5757
_strategies = new StagedStrategyChain<UnityBuildStage>(_parent?._strategies);
5858
_buildPlanStrategies = new StagedStrategyChain<BuilderStage>(_parent?._buildPlanStrategies);
5959
_registeredNames = new NamedTypesRegistry(_parent?._registeredNames);
@@ -178,7 +178,7 @@ private static string GetTypeName(object assignmentInstance)
178178
/// This is a nested class so that it can access state in the
179179
/// container that would otherwise be inaccessible.
180180
/// </remarks>
181-
private class ContainerContext : ExtensionContext
181+
private class ContainerContext : ExtensionContext, IContainerContext
182182
{
183183
private readonly UnityContainer _container;
184184

src/UnityContainer.cs

Lines changed: 29 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
using Unity.Injection;
1414
using Unity.Lifetime;
1515
using Unity.ObjectBuilder;
16-
using Unity.ObjectBuilder.Policies;
1716
using Unity.Policy;
1817
using Unity.Registration;
1918
using Unity.Resolution;
19+
using Unity.Strategy;
2020

2121
namespace Unity
2222
{
@@ -51,67 +51,52 @@ public UnityContainer()
5151
/// <param name="lifetimeManager">The <see cref="LifetimeManager"/> that controls the lifetime
5252
/// of the returned instance.</param>
5353
/// <param name="injectionMembers">Injection configuration objects.</param>
54-
/// <returns>The <see cref="UnityContainer"/> object that this method was called on (this in C#, Me in Visual Basic).</returns>
55-
public IUnityContainer RegisterType(Type typeFrom, Type typeTo, string name, LifetimeManager lifetimeManager, InjectionMember[] injectionMembers)
54+
/// <returns>The <see cref="UnityContainer"/> object that this method was called on
55+
/// (this in C#, Me in Visual Basic).</returns>
56+
public IUnityContainer RegisterType(Type typeFrom, Type typeTo, string name,
57+
LifetimeManager lifetimeManager, InjectionMember[] injectionMembers)
5658
{
57-
var to = typeTo ?? throw new ArgumentNullException(nameof(typeTo));
59+
// Validate input
60+
if (string.Empty == name) name = null;
5861

59-
if (string.IsNullOrEmpty(name))
60-
{
61-
name = null;
62-
}
62+
if (null == typeTo) throw new ArgumentNullException(nameof(typeTo));
6363

64-
if (typeFrom != null && !typeFrom.GetTypeInfo().IsGenericType && !to.GetTypeInfo().IsGenericType)
64+
if (typeFrom != null && !typeFrom.GetTypeInfo().IsGenericType && !typeTo.GetTypeInfo().IsGenericType &&
65+
!typeFrom.GetTypeInfo().IsAssignableFrom(typeTo.GetTypeInfo()))
6566
{
66-
if (!typeFrom.GetTypeInfo().IsAssignableFrom(to.GetTypeInfo()))
67-
{
68-
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Constants.TypesAreNotAssignable,
69-
typeFrom,
70-
to), nameof(typeFrom));
71-
}
67+
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Constants.TypesAreNotAssignable,
68+
typeFrom, typeTo), nameof(typeFrom));
7269
}
7370

74-
var buildType = typeFrom ?? to;
75-
var buildKey = new NamedTypeBuildKey(buildType, name);
71+
// Register Type
72+
var buildType = typeFrom ?? typeTo;
7673

77-
_policies.Set(buildKey.Type, buildKey.Name, typeof(IBuildPlanPolicy), new OverriddenBuildPlanMarkerPolicy());
78-
_policies.Clear(buildKey.Type, buildKey.Name, typeof(ILifetimePolicy));
79-
_policies.Clear(buildKey.Type, buildKey.Name, typeof(IBuildKeyMappingPolicy));
74+
// Clear build plan
75+
_policies.Set(buildType, name, typeof(IBuildPlanPolicy), new OverriddenBuildPlanMarkerPolicy());
8076

77+
// Register Type/Name
8178
_registeredNames.RegisterType(buildType, name);
8279

83-
if (typeFrom != null && typeFrom != typeTo)
84-
{
85-
if (typeFrom.GetTypeInfo().IsGenericTypeDefinition && to.GetTypeInfo().IsGenericTypeDefinition)
86-
{
87-
_policies.Set<IBuildKeyMappingPolicy>(new GenericTypeBuildKeyMappingPolicy(new NamedTypeBuildKey(to, name)),
88-
new NamedTypeBuildKey(typeFrom, name));
89-
}
90-
else
91-
{
92-
_policies.Set<IBuildKeyMappingPolicy>(new BuildKeyMappingPolicy(new NamedTypeBuildKey(to, name)), buildKey);
93-
}
94-
if ((null == injectionMembers || injectionMembers.Length == 0) && !(lifetimeManager is IRequireBuildUpPolicy))
95-
_policies.Set<IBuildPlanPolicy>(new ResolveBuildUpPolicy(), buildKey);
96-
}
97-
if (lifetimeManager != null)
98-
{
99-
SetLifetimeManager(buildType, name, lifetimeManager);
100-
}
101-
102-
Registering?.Invoke(this, new RegisterEventArgs(typeFrom, to, name, lifetimeManager));
103-
80+
// Add Injection Members to the list
10481
if (null != injectionMembers && injectionMembers.Length > 0)
10582
{
10683
foreach (var member in injectionMembers)
10784
{
10885
if (member is IInjectionFactory && null != typeFrom && typeFrom != typeTo)
10986
throw new InvalidOperationException(Constants.CannotInjectFactory);
11087

111-
member.AddPolicies(buildType, to, name, _policies);
88+
member.AddPolicies(buildType, typeTo, name, _policies);
11289
}
11390
}
11491

92+
// Register policies for each strategy
93+
// TODO: Use cached version to impreve performance
94+
foreach (var strategy in _strategies.OfType<IRegisterTypeStrategy>())
95+
strategy.RegisterType(_context, typeFrom, typeTo, name, lifetimeManager, injectionMembers);
96+
97+
// Raise event
98+
Registering?.Invoke(this, new RegisterEventArgs(typeFrom, typeTo, name, lifetimeManager));
99+
115100
return this;
116101
}
117102

@@ -322,8 +307,7 @@ public IUnityContainer RemoveAllExtensions()
322307
public IUnityContainer CreateChildContainer()
323308
{
324309
var child = new UnityContainer(this);
325-
var childContext = new ContainerContext(child);
326-
ChildContainerCreated?.Invoke(this, new ChildContainerCreatedEventArgs(childContext));
310+
ChildContainerCreated?.Invoke(this, new ChildContainerCreatedEventArgs(child._context));
327311
return child;
328312
}
329313

@@ -383,6 +367,7 @@ protected virtual void Dispose(bool disposing)
383367

384368
#endregion
385369

370+
386371
/// <summary>
387372
/// Returns information about existing registration
388373
/// </summary>

tests/Performance/Unity.Performance.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
</ItemGroup>
1515

1616
<ItemGroup>
17-
<PackageReference Include="BenchmarkDotNet" Version="0.10.10" />
17+
<PackageReference Include="BenchmarkDotNet" Version="0.10.11" />
1818
</ItemGroup>
1919

2020
<ItemGroup>

tests/Unity.Tests/Unity.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0-preview-20171012-09" />
9+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
1010
<PackageReference Include="MSTest.TestAdapter" Version="1.2.0" />
1111
<PackageReference Include="MSTest.TestFramework" Version="1.2.0" />
1212
</ItemGroup>

0 commit comments

Comments
 (0)