Skip to content

Commit 647cb77

Browse files
committed
Merge branch 'master' of https://github.com/unitycontainer/container into v5.x
2 parents 702860b + 7618e68 commit 647cb77

File tree

7 files changed

+117
-56
lines changed

7 files changed

+117
-56
lines changed

src/Injection/Validating.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public static class Validating
1212
ConstructorInfo selection = null;
1313
var ctor = (InjectionMember<ConstructorInfo, object[]>)member;
1414

15-
if (ctor.IsInitialized) throw new InvalidOperationException("Sharing InjectionConstructor between registrations is not supported");
15+
if (ctor.IsInitialized) throw new InvalidOperationException("Sharing an InjectionConstructor between registrations is not supported");
1616

1717
// Select Constructor
1818
foreach (var info in ctor.DeclaredMembers(type))
@@ -42,7 +42,7 @@ public static class Validating
4242
MethodInfo selection = null;
4343
var method = (InjectionMember<MethodInfo, object[]>)member;
4444

45-
if (method.IsInitialized) throw new InvalidOperationException("Sharing InjectionMethod between registrations is not supported");
45+
if (method.IsInitialized) throw new InvalidOperationException("Sharing an InjectionMethod between registrations is not supported");
4646

4747
// Select Method
4848
foreach (var info in type.GetDeclaredMethods())
@@ -109,7 +109,7 @@ public static class Validating
109109
var field = (InjectionMember<FieldInfo, object>)member;
110110

111111
if (field.IsInitialized) throw new InvalidOperationException(
112-
"Sharing InjectionField between registrations is not supported");
112+
"Sharing an InjectionField between registrations is not supported");
113113

114114
// Select Field
115115
foreach (var info in type.GetDeclaredFields())
@@ -158,7 +158,7 @@ public static class Validating
158158
PropertyInfo selection = null;
159159
var property = (InjectionMember<PropertyInfo, object>)member;
160160

161-
if (property.IsInitialized) throw new InvalidOperationException("Sharing InjectionProperty between registrations is not supported");
161+
if (property.IsInitialized) throw new InvalidOperationException("Sharing an InjectionProperty between registrations is not supported");
162162

163163
// Select Property
164164
foreach (var info in type.GetDeclaredProperties())

src/Processors/Constructor/ConstructorDiagnostic.cs

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Unity.Resolution;
1111
using Unity.Registration;
1212
using Unity.Injection;
13+
using System.Text.RegularExpressions;
1314

1415
namespace Unity.Processors
1516
{
@@ -102,7 +103,8 @@ public override IEnumerable<object> Select(Type type, IPolicySet registration)
102103
break;
103104

104105
default:
105-
throw new InvalidOperationException($"Multiple Injection Constructors are registered for Type {type.FullName}");
106+
return new[] { new InvalidOperationException($"Multiple Injection Constructors are registered for Type {type.FullName}",
107+
new InvalidRegistrationException()) };
106108
}
107109

108110
// Enumerate to array
@@ -137,13 +139,70 @@ public override IEnumerable<object> Select(Type type, IPolicySet registration)
137139
break;
138140

139141
default:
140-
throw new InvalidOperationException($"Multiple Constructors are annotated for injection on Type {type.FullName}");
142+
return new[] { new InvalidOperationException($"Multiple Constructors are annotated for injection on Type {type.FullName}",
143+
new InvalidRegistrationException()) };
141144
}
142145

143146
// Select default
144147
return new[] { SelectMethod(type, constructors) };
145148
}
146149

150+
protected override object SmartSelector(Type type, ConstructorInfo[] constructors)
151+
{
152+
Array.Sort(constructors, (a, b) =>
153+
{
154+
var qtd = b.GetParameters().Length.CompareTo(a.GetParameters().Length);
155+
156+
if (qtd == 0)
157+
{
158+
#if NETSTANDARD1_0 || NETCOREAPP1_0
159+
return b.GetParameters().Sum(p => p.ParameterType.GetTypeInfo().IsInterface ? 1 : 0)
160+
.CompareTo(a.GetParameters().Sum(p => p.ParameterType.GetTypeInfo().IsInterface ? 1 : 0));
161+
#else
162+
return b.GetParameters().Sum(p => p.ParameterType.IsInterface ? 1 : 0)
163+
.CompareTo(a.GetParameters().Sum(p => p.ParameterType.IsInterface ? 1 : 0));
164+
#endif
165+
}
166+
return qtd;
167+
});
168+
169+
int parametersCount = 0;
170+
ConstructorInfo bestCtor = null;
171+
172+
foreach (var ctorInfo in constructors)
173+
{
174+
var parameters = ctorInfo.GetParameters();
175+
176+
if (null != bestCtor && parametersCount > parameters.Length) return bestCtor;
177+
parametersCount = parameters.Length;
178+
179+
#if NET40
180+
if (parameters.All(p => (null != p.DefaultValue && !(p.DefaultValue is DBNull)) || CanResolve(p.ParameterType)))
181+
#else
182+
if (parameters.All(p => p.HasDefaultValue || CanResolve(p.ParameterType)))
183+
#endif
184+
{
185+
if (bestCtor == null)
186+
{
187+
bestCtor = ctorInfo;
188+
}
189+
else
190+
{
191+
var message = $"Ambiguous constructor: Failed to choose between {type.Name}{Regex.Match(bestCtor.ToString(), @"\((.*?)\)")} and {type.Name}{Regex.Match(ctorInfo.ToString(), @"\((.*?)\)")}";
192+
return new InvalidOperationException(message, new InvalidRegistrationException());
193+
}
194+
}
195+
}
196+
197+
if (bestCtor == null)
198+
{
199+
return new InvalidOperationException(
200+
$"Failed to select a constructor for {type.FullName}", new InvalidRegistrationException());
201+
}
202+
203+
return bestCtor;
204+
}
205+
147206
#endregion
148207

149208

src/Processors/Constructor/ConstructorExpression.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ public override IEnumerable<Expression> GetExpressions(Type type, IPolicySet reg
5757
.FirstOrDefault();
5858

5959
// Select constructor for the Type
60-
ConstructorInfo info;
6160
object[] resolvers = null;
61+
ConstructorInfo info = null;
6262
IEnumerable<Expression> parametersExpr;
6363

6464
switch (selection)
@@ -74,6 +74,11 @@ public override IEnumerable<Expression> GetExpressions(Type type, IPolicySet reg
7474
parametersExpr = CreateParameterExpressions(info.GetParameters(), resolvers);
7575
break;
7676

77+
case Exception exception:
78+
return new[] {Expression.IfThen(
79+
Expression.Equal(Expression.Constant(null), BuilderContextExpression.Existing),
80+
Expression.Throw(Expression.Constant(exception)))};
81+
7782
default:
7883
return NoConstructorExpr;
7984
}

src/Processors/Constructor/ConstructorProcessor.cs

Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Globalization;
44
using System.Linq;
55
using System.Reflection;
6+
using Unity.Exceptions;
67
using Unity.Injection;
78
using Unity.Policy;
89
using Unity.Registration;
@@ -113,25 +114,23 @@ public object LegacySelector(Type type, ConstructorInfo[] members)
113114
var paramLength = members[0].GetParameters().Length;
114115
if (members[1].GetParameters().Length == paramLength)
115116
{
116-
throw new InvalidOperationException(
117+
return new InvalidOperationException(
117118
string.Format(
118119
CultureInfo.CurrentCulture,
119120
"The type {0} has multiple constructors of length {1}. Unable to disambiguate.",
120121
type.GetTypeInfo().Name,
121-
paramLength));
122+
paramLength), new InvalidRegistrationException());
122123
}
123124
return members[0];
124125
}
125126
}
126127

127-
private object SmartSelector(Type type, ConstructorInfo[] constructors)
128+
protected virtual object SmartSelector(Type type, ConstructorInfo[] constructors)
128129
{
129130
Array.Sort(constructors, (a, b) =>
130131
{
131132
var qtd = b.GetParameters().Length.CompareTo(a.GetParameters().Length);
132133

133-
134-
135134
if (qtd == 0)
136135
{
137136
#if NETSTANDARD1_0 || NETCOREAPP1_0
@@ -145,62 +144,24 @@ private object SmartSelector(Type type, ConstructorInfo[] constructors)
145144
return qtd;
146145
});
147146

148-
int parametersCount = 0;
149-
ConstructorInfo bestCtor = null;
150-
HashSet<Type> bestCtorParameters = null;
151-
152147
foreach (var ctorInfo in constructors)
153148
{
154149
var parameters = ctorInfo.GetParameters();
155-
156-
if (null != bestCtor && parametersCount > parameters.Length) return bestCtor;
157-
parametersCount = parameters.Length;
158-
159150
#if NET40
160151
if (parameters.All(p => (null != p.DefaultValue && !(p.DefaultValue is DBNull)) || CanResolve(p.ParameterType)))
161152
#else
162153
if (parameters.All(p => p.HasDefaultValue || CanResolve(p.ParameterType)))
163154
#endif
164155
{
165-
if (bestCtor == null)
166-
{
167-
bestCtor = ctorInfo;
168-
}
169-
else
170-
{
171-
// Since we're visiting constructors in decreasing order of number of parameters,
172-
// we'll only see ambiguities or supersets once we've seen a 'bestConstructor'.
173-
174-
if (null == bestCtorParameters)
175-
{
176-
bestCtorParameters = new HashSet<Type>(
177-
bestCtor.GetParameters().Select(p => p.ParameterType));
178-
}
179-
180-
if (!bestCtorParameters.IsSupersetOf(parameters.Select(p => p.ParameterType)))
181-
{
182-
if (bestCtorParameters.All(p => p.GetTypeInfo().IsInterface) &&
183-
!parameters.All(p => p.ParameterType.GetTypeInfo().IsInterface))
184-
return bestCtor;
185-
186-
throw new InvalidOperationException($"Failed to select a constructor for {type.FullName}");
187-
}
188-
189-
return bestCtor;
190-
}
156+
return ctorInfo;
191157
}
192158
}
193159

194-
if (bestCtor == null)
195-
{
196-
throw new InvalidOperationException(
197-
$"Failed to select a constructor for {type.FullName}");
198-
}
199-
200-
return bestCtor;
160+
return new InvalidOperationException(
161+
$"Failed to select a constructor for {type.FullName}", new InvalidRegistrationException());
201162
}
202163

203-
private bool CanResolve(Type type)
164+
protected bool CanResolve(Type type)
204165
{
205166
#if NETSTANDARD1_0 || NETCOREAPP1_0
206167
var info = type.GetTypeInfo();

src/Processors/Constructor/ConstructorResolution.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ public override ResolveDelegate<BuilderContext> GetResolver(Type type, IPolicySe
3636
resolvers = injectionMember.Data;
3737
break;
3838

39+
case Exception exception:
40+
return (ref BuilderContext c) =>
41+
{
42+
if (null == c.Existing)
43+
throw exception;
44+
45+
return c.Existing;
46+
};
47+
3948
default:
4049
return (ref BuilderContext c) =>
4150
{

tests/Unity.Diagnostic/Constructor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public override IUnityContainer GetContainer()
3535
}
3636

3737
[TestClass]
38-
public class Validation : Unity.Specification.Diagnostic.Constructor.Validation.SpecificationTests
38+
public class Injection : Unity.Specification.Diagnostic.Constructor.Injection.SpecificationTests
3939
{
4040
public override IUnityContainer GetContainer()
4141
{
@@ -78,7 +78,7 @@ public override IUnityContainer GetContainer()
7878
}
7979

8080
[TestClass]
81-
public class Validation : Unity.Specification.Diagnostic.Constructor.Validation.SpecificationTests
81+
public class Injection : Unity.Specification.Diagnostic.Constructor.Injection.SpecificationTests
8282
{
8383
public override IUnityContainer GetContainer()
8484
{

tests/Unity.Specification/BuildUp.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using Unity;
3+
4+
namespace Compiled
5+
{
6+
[TestClass]
7+
public class BuildUp : Unity.Specification.BuildUp.SpecificationTests
8+
{
9+
public override IUnityContainer GetContainer()
10+
{
11+
return new UnityContainer().AddExtension(new ForceCompillation());
12+
}
13+
}
14+
}
15+
16+
17+
namespace Resolved
18+
{
19+
[TestClass]
20+
public class BuildUp : Unity.Specification.BuildUp.SpecificationTests
21+
{
22+
public override IUnityContainer GetContainer()
23+
{
24+
return new UnityContainer().AddExtension(new ForceActivation());
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)