Skip to content

Commit 7f601e5

Browse files
committed
Improvements to Diagnostic extension
1 parent 0a04222 commit 7f601e5

10 files changed

Lines changed: 254 additions & 96 deletions

File tree

src/Injection/Validating.cs

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public static class Validating
4545
if (method.IsInitialized) throw new InvalidOperationException("Sharing InjectionMethod between registrations is not supported");
4646

4747
// Select Method
48-
foreach (var info in method.DeclaredMembers(type))
48+
foreach (var info in type.GetDeclaredMethods())
4949
{
5050
if (!method.Data.MatchMemberInfo(info)) continue;
5151

@@ -68,26 +68,34 @@ public static class Validating
6868
if (selection.IsStatic)
6969
{
7070
throw new ArgumentException(
71-
$"The method {type?.Name}.{method.Name}({method.Data.Signature()}) is static. Static methods cannot be injected.");
71+
$"Static method {method.Name} on type '{selection.DeclaringType.Name}' cannot be injected");
7272
}
7373

74+
if (selection.IsPrivate)
75+
throw new InvalidOperationException(
76+
$"Private method '{method.Name}' on type '{selection.DeclaringType.Name}' cannot be injected");
77+
78+
if (selection.IsFamily)
79+
throw new InvalidOperationException(
80+
$"Protected method '{method.Name}' on type '{selection.DeclaringType.Name}' cannot be injected");
81+
7482
if (selection.IsGenericMethodDefinition)
7583
{
7684
throw new ArgumentException(
77-
$"The method {type?.Name}.{method.Name}({method.Data.Signature()}) is an open generic method. Open generic methods cannot be injected.");
85+
$"Open generic method {method.Name} on type '{selection.DeclaringType.Name}' cannot be injected");
7886
}
7987

8088
var parameters = selection.GetParameters();
8189
if (parameters.Any(param => param.IsOut))
8290
{
8391
throw new ArgumentException(
84-
$"The method {type?.Name}.{method.Name}({method.Data.Signature()}) has at least one out parameter. Methods with out parameters cannot be injected.");
92+
$"Method {method.Name} on type '{selection.DeclaringType.Name}' cannot be injected. Methods with 'out' parameters are not injectable.");
8593
}
8694

8795
if (parameters.Any(param => param.ParameterType.IsByRef))
8896
{
8997
throw new ArgumentException(
90-
$"The method {type?.Name}.{method.Name}({method.Data.Signature()}) has at least one ref parameter.Methods with ref parameters cannot be injected.");
98+
$"Method {method.Name} on type '{selection.DeclaringType.Name}' cannot be injected. Methods with 'ref' parameters are not injectable.");
9199
}
92100

93101
return selection;
@@ -100,10 +108,11 @@ public static class Validating
100108
FieldInfo selection = null;
101109
var field = (InjectionMember<FieldInfo, object>)member;
102110

103-
if (field.IsInitialized) throw new InvalidOperationException("Sharing InjectionField between registrations is not supported");
111+
if (field.IsInitialized) throw new InvalidOperationException(
112+
"Sharing InjectionField between registrations is not supported");
104113

105114
// Select Field
106-
foreach (var info in field.DeclaredMembers(type))
115+
foreach (var info in type.GetDeclaredFields())
107116
{
108117
if (info.Name != field.Name) continue;
109118

@@ -118,17 +127,25 @@ public static class Validating
118127
$"Injected field '{field.Name}' could not be matched with any public field on type '{type?.Name}'.");
119128
}
120129

130+
if (selection.IsStatic)
131+
throw new InvalidOperationException(
132+
$"Static field '{selection.Name}' on type '{type?.Name}' cannot be injected");
133+
121134
if (selection.IsInitOnly)
122-
{
123-
throw new ArgumentException(
124-
$"Field '{selection.Name}' on type '{type?.Name}' is Read Only and can not be injected.");
125-
}
135+
throw new InvalidOperationException(
136+
$"Readonly field '{selection.Name}' on type '{type?.Name}' cannot be injected");
137+
138+
if (selection.IsPrivate)
139+
throw new InvalidOperationException(
140+
$"Private field '{selection.Name}' on type '{type?.Name}' cannot be injected");
141+
142+
if (selection.IsFamily)
143+
throw new InvalidOperationException(
144+
$"Protected field '{selection.Name}' on type '{type?.Name}' cannot be injected");
126145

127146
if (!field.Data.Matches(selection.FieldType))
128-
{
129147
throw new ArgumentException(
130148
$"Injected data '{field.Data}' could not be matched with type of field '{selection.FieldType.Name}'.");
131-
}
132149

133150
return selection;
134151
};
@@ -144,7 +161,7 @@ public static class Validating
144161
if (property.IsInitialized) throw new InvalidOperationException("Sharing InjectionProperty between registrations is not supported");
145162

146163
// Select Property
147-
foreach (var info in property.DeclaredMembers(type))
164+
foreach (var info in type.GetDeclaredProperties())
148165
{
149166
if (info.Name != property.Name) continue;
150167

@@ -156,14 +173,30 @@ public static class Validating
156173
if (null == selection)
157174
{
158175
throw new ArgumentException(
159-
$"Injected property '{property.Name}' could not be matched with any public property on type '{type?.Name}'.");
176+
$"Injected property '{property.Name}' could not be matched with any property on type '{type?.Name}'.");
160177
}
161178

162179
if (!selection.CanWrite)
163-
{
164-
throw new ArgumentException(
165-
$"Property '{selection.Name}' on type '{type?.Name}' is Read Only and can not be injected.");
166-
}
180+
throw new InvalidOperationException(
181+
$"Readonly property '{selection.Name}' on type '{type?.Name}' cannot be injected");
182+
183+
if (0 != selection.GetIndexParameters().Length)
184+
throw new InvalidOperationException(
185+
$"Indexer '{selection.Name}' on type '{type?.Name}' cannot be injected");
186+
187+
var setter = selection.GetSetMethod(true);
188+
189+
if (setter.IsStatic)
190+
throw new InvalidOperationException(
191+
$"Static property '{selection.Name}' on type '{type?.Name}' cannot be injected");
192+
193+
if (setter.IsPrivate)
194+
throw new InvalidOperationException(
195+
$"Private property '{selection.Name}' on type '{type?.Name}' cannot be injected");
196+
197+
if (setter.IsFamily)
198+
throw new InvalidOperationException(
199+
$"Protected property '{selection.Name}' on type '{type?.Name}' cannot be injected");
167200

168201
if (!property.Data.Matches(selection.PropertyType))
169202
{
@@ -173,5 +206,6 @@ public static class Validating
173206

174207
return selection;
175208
};
209+
176210
}
177211
}

src/Processors/Abstracts/MemberProcessor.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,6 @@ public virtual IEnumerable<object> Select(Type type, IPolicySet registration)
216216

217217
protected abstract IEnumerable<TMemberInfo> DeclaredMembers(Type type);
218218

219-
protected virtual void ValidateMember(TMemberInfo info) { }
220-
221219
protected object PreProcessResolver(TMemberInfo info, object resolver)
222220
{
223221
switch (resolver)

src/Processors/Fields/FieldDiagnostic.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq.Expressions;
34
using System.Reflection;
45
using Unity.Builder;
6+
using Unity.Injection;
57
using Unity.Policy;
8+
using Unity.Registration;
69
using Unity.Resolution;
710

811
namespace Unity.Processors
@@ -20,6 +23,54 @@ public FieldDiagnostic(IPolicySet policySet) : base(policySet)
2023

2124
#region Overrides
2225

26+
public override IEnumerable<object> Select(Type type, IPolicySet registration)
27+
{
28+
HashSet<object> memberSet = new HashSet<object>();
29+
30+
// Select Injected Members
31+
if (null != ((InternalRegistration)registration).InjectionMembers)
32+
{
33+
foreach (var injectionMember in ((InternalRegistration)registration).InjectionMembers)
34+
{
35+
if (injectionMember is InjectionMember<FieldInfo, object> && memberSet.Add(injectionMember))
36+
yield return injectionMember;
37+
}
38+
}
39+
40+
// Select Attributed members
41+
foreach (var member in type.GetDeclaredFields())
42+
{
43+
for (var i = 0; i < AttributeFactories.Length; i++)
44+
{
45+
#if NET40
46+
if (!member.IsDefined(AttributeFactories[i].Type, true) ||
47+
#else
48+
if (!member.IsDefined(AttributeFactories[i].Type) ||
49+
#endif
50+
!memberSet.Add(member)) continue;
51+
52+
if (member.IsStatic)
53+
throw new InvalidOperationException(
54+
$"Static field '{member.Name}' on type '{type?.Name}' is marked for injection. Static fields cannot be injected");
55+
56+
if (member.IsInitOnly)
57+
throw new InvalidOperationException(
58+
$"Readonly field '{member.Name}' on type '{type?.Name}' is marked for injection. Readonly fields cannot be injected");
59+
60+
if (member.IsPrivate)
61+
throw new InvalidOperationException(
62+
$"Private field '{member.Name}' on type '{type?.Name}' is marked for injection. Private fields cannot be injected");
63+
64+
if (member.IsFamily)
65+
throw new InvalidOperationException(
66+
$"Protected field '{member.Name}' on type '{type?.Name}' is marked for injection. Protected fields cannot be injected");
67+
68+
yield return member;
69+
break;
70+
}
71+
}
72+
}
73+
2374
protected override Expression GetResolverExpression(FieldInfo field, object resolver)
2475
{
2576
var ex = Expression.Variable(typeof(Exception));

src/Processors/Fields/FieldProcessor.cs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using System.Linq.Expressions;
45
using System.Reflection;
56
using Unity.Builder;
@@ -24,18 +25,9 @@ public FieldProcessor(IPolicySet policySet)
2425

2526
protected override IEnumerable<FieldInfo> DeclaredMembers(Type type)
2627
{
27-
var info = type.GetTypeInfo();
28-
while (null != info)
29-
{
30-
foreach (var member in info.DeclaredFields)
31-
{
32-
if (!member.IsFamily && !member.IsPrivate &&
33-
!member.IsInitOnly && !member.IsStatic)
34-
yield return member;
35-
}
36-
37-
info = info.BaseType?.GetTypeInfo();
38-
}
28+
return type.GetDeclaredFields()
29+
.Where(member => !member.IsFamily && !member.IsPrivate &&
30+
!member.IsInitOnly && !member.IsStatic);
3931
}
4032

4133
protected override Type MemberType(FieldInfo info) => info.FieldType;

src/Processors/Methods/MethodDiagnostic.cs

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
24
using System.Linq;
35
using System.Linq.Expressions;
46
using System.Reflection;
57
using Unity.Builder;
8+
using Unity.Exceptions;
9+
using Unity.Injection;
610
using Unity.Policy;
11+
using Unity.Registration;
712
using Unity.Resolution;
813

914
namespace Unity.Processors
@@ -22,10 +27,74 @@ public MethodDiagnostic(IPolicySet policySet)
2227

2328
#region Overrides
2429

25-
protected override Expression GetResolverExpression(MethodInfo info, object resolvers)
30+
public override IEnumerable<object> Select(Type type, IPolicySet registration)
2631
{
27-
ValidateMember(info);
32+
HashSet<object> memberSet = new HashSet<object>();
33+
34+
// Select Injected Members
35+
if (null != ((InternalRegistration)registration).InjectionMembers)
36+
{
37+
foreach (var injectionMember in ((InternalRegistration)registration).InjectionMembers)
38+
{
39+
if (injectionMember is InjectionMember<MethodInfo, object[]> && memberSet.Add(injectionMember))
40+
yield return injectionMember;
41+
}
42+
}
43+
44+
// Select Attributed members
45+
foreach (var member in type.GetDeclaredMethods())
46+
{
47+
for (var i = 0; i < AttributeFactories.Length; i++)
48+
{
49+
#if NET40
50+
if (!member.IsDefined(AttributeFactories[i].Type, true) ||
51+
#else
52+
if (!member.IsDefined(AttributeFactories[i].Type) ||
53+
#endif
54+
!memberSet.Add(member)) continue;
55+
56+
// Validate
57+
if (member.IsStatic)
58+
{
59+
throw new ArgumentException(
60+
$"Static method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Static methods cannot be injected");
61+
}
62+
63+
if (member.IsPrivate)
64+
throw new InvalidOperationException(
65+
$"Private method '{member.Name}' on type '{member.DeclaringType.Name}' is marked for injection. Private methods cannot be injected");
2866

67+
if (member.IsFamily)
68+
throw new InvalidOperationException(
69+
$"Protected method '{member.Name}' on type '{member.DeclaringType.Name}' is marked for injection. Protected methods cannot be injected");
70+
71+
if (member.IsGenericMethodDefinition)
72+
{
73+
throw new ArgumentException(
74+
$"Open generic method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Open generic methods cannot be injected.");
75+
}
76+
77+
var parameters = member.GetParameters();
78+
if (parameters.Any(param => param.IsOut))
79+
{
80+
throw new ArgumentException(
81+
$"Method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Methods with 'out' parameters cannot be injected.");
82+
}
83+
84+
if (parameters.Any(param => param.ParameterType.IsByRef))
85+
{
86+
throw new ArgumentException(
87+
$"Method {member.Name} on type '{member.DeclaringType.Name}' is marked for injection. Methods with 'ref' parameters cannot be injected.");
88+
}
89+
90+
yield return member;
91+
break;
92+
}
93+
}
94+
}
95+
96+
protected override Expression GetResolverExpression(MethodInfo info, object resolvers)
97+
{
2998
var ex = Expression.Variable(typeof(Exception));
3099
var exData = Expression.MakeMemberAccess(ex, DataProperty);
31100
var block = Expression.Block(typeof(void),
@@ -44,8 +113,6 @@ protected override Expression GetResolverExpression(MethodInfo info, object reso
44113

45114
protected override ResolveDelegate<BuilderContext> GetResolverDelegate(MethodInfo info, object resolvers)
46115
{
47-
ValidateMember(info);
48-
49116
var parameterResolvers = CreateDiagnosticParameterResolvers(info.GetParameters(), resolvers).ToArray();
50117
return (ref BuilderContext c) =>
51118
{

0 commit comments

Comments
 (0)