Code Coverage Statistics for Source File
Newtonsoft.Json\Utilities\ReflectionUtils.cs
Symbol Coverage: 76.99% (271 of 352)
Branch Coverage: 75.81% (141 of 186)
Cyclomatic Complexity Avg: 2.71 Max:9
Code Lines: 335
Symbol Coverage Trend
View:
L | V | Source |
---|---|---|
1 |
#region License |
|
2 |
// Copyright (c) 2007 James Newton-King |
|
3 |
// |
|
4 |
// Permission is hereby granted, free of charge, to any person |
|
5 |
// obtaining a copy of this software and associated documentation |
|
6 |
// files (the "Software"), to deal in the Software without |
|
7 |
// restriction, including without limitation the rights to use, |
|
8 |
// copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
9 |
// copies of the Software, and to permit persons to whom the |
|
10 |
// Software is furnished to do so, subject to the following |
|
11 |
// conditions: |
|
12 |
// |
|
13 |
// The above copyright notice and this permission notice shall be |
|
14 |
// included in all copies or substantial portions of the Software. |
|
15 |
// |
|
16 |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
17 |
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|
18 |
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
19 |
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|
20 |
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|
21 |
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
22 |
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|
23 |
// OTHER DEALINGS IN THE SOFTWARE. |
|
24 |
#endregion |
|
25 |
||
26 |
using System; |
|
27 |
using System.Collections.Generic; |
|
28 |
using System.Reflection; |
|
29 |
using System.Collections; |
|
30 |
using System.Linq; |
|
31 |
using System.Globalization; |
|
32 |
using System.Runtime.Serialization.Formatters; |
|
33 |
||
34 |
namespace Newtonsoft.Json.Utilities |
|
35 |
{ |
|
36 |
internal static class ReflectionUtils |
|
37 |
{ |
|
38 |
public static Type GetObjectType(object v) |
|
39 |
{ |
|
40 |
210719 |
return (v != null) ? v.GetType() : null;
|
41 |
210719 |
}
|
42 |
||
43 |
public static string GetTypeName(Type t, FormatterAssemblyStyle assemblyFormat) |
|
44 |
{ |
|
45 |
16 |
switch (assemblyFormat)
|
46 |
{ |
|
47 |
case FormatterAssemblyStyle.Simple: |
|
48 |
10 |
return t.FullName + ", " + t.Assembly.GetName().Name;
|
49 |
case FormatterAssemblyStyle.Full: |
|
50 |
6 |
return t.AssemblyQualifiedName;
|
51 |
default: |
|
52 |
0 |
throw new ArgumentOutOfRangeException();
|
53 |
} |
|
54 |
16 |
}
|
55 |
||
56 |
public static bool IsInstantiatableType(Type t) |
|
57 |
{ |
|
58 |
20051 |
ValidationUtils.ArgumentNotNull(t, "t");
|
59 |
||
60 |
20051 |
if (t.IsAbstract || t.IsInterface || t.IsArray || t.IsGenericTypeDefinition || t == typeof(void))
|
61 |
0 |
return false;
|
62 |
||
63 |
20051 |
if (!HasDefaultConstructor(t))
|
64 |
0 |
return false;
|
65 |
||
66 |
20051 |
return true;
|
67 |
20051 |
}
|
68 |
||
69 |
public static bool HasDefaultConstructor(Type t) |
|
70 |
{ |
|
71 |
20051 |
return HasDefaultConstructor(t, false);
|
72 |
20051 |
}
|
73 |
||
74 |
public static bool HasDefaultConstructor(Type t, bool nonPublic) |
|
75 |
{ |
|
76 |
20360 |
ValidationUtils.ArgumentNotNull(t, "t");
|
77 |
||
78 |
20360 |
if (t.IsValueType)
|
79 |
46 |
return true;
|
80 |
||
81 |
20314 |
return (GetDefaultConstructor(t, nonPublic) != null);
|
82 |
20360 |
}
|
83 |
||
84 |
public static ConstructorInfo GetDefaultConstructor(Type t) |
|
85 |
{ |
|
86 |
209 |
return GetDefaultConstructor(t, false);
|
87 |
209 |
}
|
88 |
||
89 |
public static ConstructorInfo GetDefaultConstructor(Type t, bool nonPublic) |
|
90 |
{ |
|
91 |
20523 |
BindingFlags accessModifier = BindingFlags.Public;
|
92 |
|
|
93 |
20523 |
if (nonPublic)
|
94 |
263 |
accessModifier = accessModifier | BindingFlags.NonPublic;
|
95 |
||
96 |
20523 |
return t.GetConstructor(accessModifier | BindingFlags.Instance, null, new Type[0], null);
|
97 |
20523 |
}
|
98 |
||
99 |
public static bool IsNullable(Type t) |
|
100 |
{ |
|
101 |
20276 |
ValidationUtils.ArgumentNotNull(t, "t");
|
102 |
||
103 |
20276 |
if (t.IsValueType)
|
104 |
116 |
return IsNullableType(t);
|
105 |
||
106 |
20160 |
return true;
|
107 |
20276 |
}
|
108 |
||
109 |
public static bool IsNullableType(Type t) |
|
110 |
{ |
|
111 |
40922 |
ValidationUtils.ArgumentNotNull(t, "t");
|
112 |
||
113 |
40922 |
return (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
|
114 |
40922 |
}
|
115 |
||
116 |
//public static bool IsValueTypeUnitializedValue(ValueType value) |
|
117 |
//{ |
|
118 |
// if (value == null) |
|
119 |
// return true; |
|
120 |
||
121 |
// return value.Equals(CreateUnitializedValue(value.GetType())); |
|
122 |
//} |
|
123 |
||
124 |
public static bool IsUnitializedValue(object value) |
|
125 |
{ |
|
126 |
0 |
if (value == null)
|
127 |
{ |
|
128 |
0 |
return true;
|
129 |
} |
|
130 |
else |
|
131 |
{ |
|
132 |
0 |
object unitializedValue = CreateUnitializedValue(value.GetType());
|
133 |
0 |
return value.Equals(unitializedValue);
|
134 |
} |
|
135 |
0 |
}
|
136 |
||
137 |
public static object CreateUnitializedValue(Type type) |
|
138 |
{ |
|
139 |
0 |
ValidationUtils.ArgumentNotNull(type, "type");
|
140 |
||
141 |
0 |
if (type.IsGenericTypeDefinition)
|
142 |
0 |
throw new ArgumentException("Type {0} is a generic type definition and cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, type), "type");
|
143 |
||
144 |
0 |
if (type.IsClass || type.IsInterface || type == typeof(void))
|
145 |
0 |
return null;
|
146 |
0 |
else if (type.IsValueType)
|
147 |
0 |
return Activator.CreateInstance(type);
|
148 |
else |
|
149 |
0 |
throw new ArgumentException("Type {0} cannot be instantiated.".FormatWith(CultureInfo.InvariantCulture, type), "type");
|
150 |
0 |
}
|
151 |
||
152 |
public static bool IsPropertyIndexed(PropertyInfo property) |
|
153 |
{ |
|
154 |
0 |
ValidationUtils.ArgumentNotNull(property, "property");
|
155 |
||
156 |
0 |
return !CollectionUtils.IsNullOrEmpty<ParameterInfo>(property.GetIndexParameters());
|
157 |
0 |
}
|
158 |
||
159 |
public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition) |
|
160 |
{ |
|
161 |
Type implementingType; |
|
162 |
235 |
return ImplementsGenericDefinition(type, genericInterfaceDefinition, out implementingType);
|
163 |
235 |
}
|
164 |
||
165 |
public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition, out Type implementingType) |
|
166 |
{ |
|
167 |
348 |
ValidationUtils.ArgumentNotNull(type, "type");
|
168 |
348 |
ValidationUtils.ArgumentNotNull(genericInterfaceDefinition, "genericInterfaceDefinition");
|
169 |
||
170 |
348 |
if (!genericInterfaceDefinition.IsInterface || !genericInterfaceDefinition.IsGenericTypeDefinition)
|
171 |
0 |
throw new ArgumentNullException("'{0}' is not a generic interface definition.".FormatWith(CultureInfo.InvariantCulture, genericInterfaceDefinition));
|
172 |
||
173 |
348 |
if (type.IsInterface)
|
174 |
{ |
|
175 |
16 |
if (type.IsGenericType)
|
176 |
{ |
|
177 |
13 |
Type interfaceDefinition = type.GetGenericTypeDefinition();
|
178 |
||
179 |
13 |
if (genericInterfaceDefinition == interfaceDefinition)
|
180 |
{ |
|
181 |
4 |
implementingType = type;
|
182 |
4 |
return true;
|
183 |
} |
|
184 |
} |
|
185 |
} |
|
186 |
||
187 |
344 |
foreach (Type i in type.GetInterfaces())
|
188 |
{ |
|
189 |
713 |
if (i.IsGenericType)
|
190 |
{ |
|
191 |
344 |
Type interfaceDefinition = i.GetGenericTypeDefinition();
|
192 |
||
193 |
344 |
if (genericInterfaceDefinition == interfaceDefinition)
|
194 |
{ |
|
195 |
94 |
implementingType = i;
|
196 |
94 |
return true;
|
197 |
} |
|
198 |
} |
|
199 |
} |
|
200 |
||
201 |
250 |
implementingType = null;
|
202 |
250 |
return false;
|
203 |
348 |
}
|
204 |
||
205 |
public static bool AssignableToTypeName(this Type type, string fullTypeName, out Type match) |
|
206 |
{ |
|
207 |
813 |
Type current = type;
|
208 |
||
209 |
2713 |
while (current != null)
|
210 |
{ |
|
211 |
1909 |
if (string.Equals(current.FullName, fullTypeName, StringComparison.Ordinal))
|
212 |
{ |
|
213 |
9 |
match = current;
|
214 |
9 |
return true;
|
215 |
} |
|
216 |
||
217 |
1900 |
current = current.BaseType;
|
218 |
} |
|
219 |
||
220 |
804 |
foreach (Type i in type.GetInterfaces())
|
221 |
{ |
|
222 |
1591 |
if (string.Equals(i.Name, fullTypeName, StringComparison.Ordinal))
|
223 |
{ |
|
224 |
0 |
match = type;
|
225 |
0 |
return true;
|
226 |
} |
|
227 |
} |
|
228 |
||
229 |
804 |
match = null;
|
230 |
804 |
return false;
|
231 |
813 |
}
|
232 |
||
233 |
public static bool AssignableToTypeName(this Type type, string fullTypeName) |
|
234 |
{ |
|
235 |
Type match; |
|
236 |
640 |
return type.AssignableToTypeName(fullTypeName, out match);
|
237 |
640 |
}
|
238 |
||
239 |
public static bool InheritsGenericDefinition(Type type, Type genericClassDefinition) |
|
240 |
{ |
|
241 |
Type implementingType; |
|
242 |
17 |
return InheritsGenericDefinition(type, genericClassDefinition, out implementingType);
|
243 |
17 |
}
|
244 |
||
245 |
public static bool InheritsGenericDefinition(Type type, Type genericClassDefinition, out Type implementingType) |
|
246 |
{ |
|
247 |
20069 |
ValidationUtils.ArgumentNotNull(type, "type");
|
248 |
20069 |
ValidationUtils.ArgumentNotNull(genericClassDefinition, "genericClassDefinition");
|
249 |
||
250 |
20069 |
if (!genericClassDefinition.IsClass || !genericClassDefinition.IsGenericTypeDefinition)
|
251 |
0 |
throw new ArgumentNullException("'{0}' is not a generic class definition.".FormatWith(CultureInfo.InvariantCulture, genericClassDefinition));
|
252 |
||
253 |
20069 |
return InheritsGenericDefinitionInternal(type, genericClassDefinition, out implementingType);
|
254 |
20069 |
}
|
255 |
||
256 |
private static bool InheritsGenericDefinitionInternal(Type currentType, Type genericClassDefinition, out Type implementingType) |
|
257 |
{ |
|
258 |
40147 |
if (currentType.IsGenericType)
|
259 |
{ |
|
260 |
20067 |
Type currentGenericClassDefinition = currentType.GetGenericTypeDefinition();
|
261 |
||
262 |
20067 |
if (genericClassDefinition == currentGenericClassDefinition)
|
263 |
{ |
|
264 |
2 |
implementingType = currentType;
|
265 |
2 |
return true;
|
266 |
} |
|
267 |
} |
|
268 |
||
269 |
40145 |
if (currentType.BaseType == null)
|
270 |
{ |
|
271 |
20067 |
implementingType = null;
|
272 |
20067 |
return false;
|
273 |
} |
|
274 |
||
275 |
20078 |
return InheritsGenericDefinitionInternal(currentType.BaseType, genericClassDefinition, out implementingType);
|
276 |
40147 |
}
|
277 |
||
278 |
/// <summary> |
|
279 |
/// Gets the type of the typed collection's items. |
|
280 |
/// </summary> |
|
281 |
/// <param name="type">The type.</param> |
|
282 |
/// <returns>The type of the typed collection's items.</returns> |
|
283 |
public static Type GetCollectionItemType(Type type) |
|
284 |
{ |
|
285 |
70 |
ValidationUtils.ArgumentNotNull(type, "type");
|
286 |
Type genericListType; |
|
287 |
||
288 |
70 |
if (type.IsArray)
|
289 |
{ |
|
290 |
40 |
return type.GetElementType();
|
291 |
} |
|
292 |
30 |
else if (ImplementsGenericDefinition(type, typeof(IEnumerable<>), out genericListType))
|
293 |
{ |
|
294 |
23 |
if (genericListType.IsGenericTypeDefinition)
|
295 |
0 |
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
|
296 |
||
297 |
23 |
return genericListType.GetGenericArguments()[0];
|
298 |
} |
|
299 |
7 |
else if (typeof(IEnumerable).IsAssignableFrom(type))
|
300 |
{ |
|
301 |
7 |
return null;
|
302 |
} |
|
303 |
else |
|
304 |
{ |
|
305 |
0 |
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
|
306 |
} |
|
307 |
70 |
}
|
308 |
||
309 |
public static void GetDictionaryKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType) |
|
310 |
{ |
|
311 |
4 |
ValidationUtils.ArgumentNotNull(dictionaryType, "type");
|
312 |
||
313 |
Type genericDictionaryType; |
|
314 |
4 |
if (ImplementsGenericDefinition(dictionaryType, typeof(IDictionary<,>), out genericDictionaryType))
|
315 |
{ |
|
316 |
3 |
if (genericDictionaryType.IsGenericTypeDefinition)
|
317 |
0 |
throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType));
|
318 |
||
319 |
3 |
Type[] dictionaryGenericArguments = genericDictionaryType.GetGenericArguments();
|
320 |
||
321 |
3 |
keyType = dictionaryGenericArguments[0];
|
322 |
3 |
valueType = dictionaryGenericArguments[1];
|
323 |
3 |
return;
|
324 |
} |
|
325 |
1 |
else if (typeof(IDictionary).IsAssignableFrom(dictionaryType))
|
326 |
{ |
|
327 |
1 |
keyType = null;
|
328 |
1 |
valueType = null;
|
329 |
1 |
return;
|
330 |
} |
|
331 |
else |
|
332 |
{ |
|
333 |
0 |
throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType));
|
334 |
} |
|
335 |
4 |
}
|
336 |
||
337 |
public static Type GetDictionaryValueType(Type dictionaryType) |
|
338 |
{ |
|
339 |
Type keyType; |
|
340 |
Type valueType; |
|
341 |
1 |
GetDictionaryKeyValueTypes(dictionaryType, out keyType, out valueType);
|
342 |
||
343 |
1 |
return valueType;
|
344 |
1 |
}
|
345 |
||
346 |
public static Type GetDictionaryKeyType(Type dictionaryType) |
|
347 |
{ |
|
348 |
Type keyType; |
|
349 |
Type valueType; |
|
350 |
1 |
GetDictionaryKeyValueTypes(dictionaryType, out keyType, out valueType);
|
351 |
||
352 |
1 |
return keyType;
|
353 |
1 |
}
|
354 |
||
355 |
/// <summary> |
|
356 |
/// Tests whether the list's items are their unitialized value. |
|
357 |
/// </summary> |
|
358 |
/// <param name="list">The list.</param> |
|
359 |
/// <returns>Whether the list's items are their unitialized value</returns> |
|
360 |
public static bool ItemsUnitializedValue<T>(IList<T> list) |
|
361 |
{ |
|
362 |
0 |
ValidationUtils.ArgumentNotNull(list, "list");
|
363 |
||
364 |
0 |
Type elementType = GetCollectionItemType(list.GetType());
|
365 |
||
366 |
0 |
if (elementType.IsValueType)
|
367 |
{ |
|
368 |
0 |
object unitializedValue = CreateUnitializedValue(elementType);
|
369 |
||
370 |
0 |
for (int i = 0; i < list.Count; i++) |
371 |
{ |
|
372 |
0 |
if (!list[i].Equals(unitializedValue))
|
373 |
0 |
return false;
|
374 |
} |
|
375 |
} |
|
376 |
0 |
else if (elementType.IsClass)
|
377 |
{ |
|
378 |
0 |
for (int i = 0; i < list.Count; i++) |
379 |
{ |
|
380 |
0 |
object value = list[i];
|
381 |
||
382 |
0 |
if (value != null)
|
383 |
0 |
return false;
|
384 |
} |
|
385 |
} |
|
386 |
else |
|
387 |
{ |
|
388 |
0 |
throw new Exception("Type {0} is neither a ValueType or a Class.".FormatWith(CultureInfo.InvariantCulture, elementType));
|
389 |
} |
|
390 |
||
391 |
0 |
return true;
|
392 |
0 |
}
|
393 |
||
394 |
/// <summary> |
|
395 |
/// Gets the member's underlying type. |
|
396 |
/// </summary> |
|
397 |
/// <param name="member">The member.</param> |
|
398 |
/// <returns>The underlying type of the member.</returns> |
|
399 |
public static Type GetMemberUnderlyingType(MemberInfo member) |
|
400 |
{ |
|
401 |
161795 |
ValidationUtils.ArgumentNotNull(member, "member");
|
402 |
||
403 |
161795 |
switch (member.MemberType)
|
404 |
{ |
|
405 |
case MemberTypes.Field: |
|
406 |
20503 |
return ((FieldInfo)member).FieldType;
|
407 |
case MemberTypes.Property: |
|
408 |
141292 |
return ((PropertyInfo)member).PropertyType;
|
409 |
case MemberTypes.Event: |
|
410 |
0 |
return ((EventInfo)member).EventHandlerType;
|
411 |
default: |
|
412 |
0 |
throw new ArgumentException("MemberInfo must be of type FieldInfo, PropertyInfo or EventInfo", "member");
|
413 |
} |
|
414 |
161795 |
}
|
415 |
||
416 |
/// <summary> |
|
417 |
/// Determines whether the member is an indexed property. |
|
418 |
/// </summary> |
|
419 |
/// <param name="member">The member.</param> |
|
420 |
/// <returns> |
|
421 |
/// <c>true</c> if the member is an indexed property; otherwise, <c>false</c>. |
|
422 |
/// </returns> |
|
423 |
public static bool IsIndexedProperty(MemberInfo member) |
|
424 |
{ |
|
425 |
1725 |
ValidationUtils.ArgumentNotNull(member, "member");
|
426 |
||
427 |
1725 |
PropertyInfo propertyInfo = member as PropertyInfo;
|
428 |
||
429 |
1725 |
if (propertyInfo != null)
|
430 |
972 |
return IsIndexedProperty(propertyInfo);
|
431 |
else |
|
432 |
753 |
return false;
|
433 |
1725 |
}
|
434 |
||
435 |
/// <summary> |
|
436 |
/// Determines whether the property is an indexed property. |
|
437 |
/// </summary> |
|
438 |
/// <param name="property">The property.</param> |
|
439 |
/// <returns> |
|
440 |
/// <c>true</c> if the property is an indexed property; otherwise, <c>false</c>. |
|
441 |
/// </returns> |
|
442 |
public static bool IsIndexedProperty(PropertyInfo property) |
|
443 |
{ |
|
444 |
972 |
ValidationUtils.ArgumentNotNull(property, "property");
|
445 |
||
446 |
972 |
return (property.GetIndexParameters().Length > 0);
|
447 |
972 |
}
|
448 |
||
449 |
/// <summary> |
|
450 |
/// Gets the member's value on the object. |
|
451 |
/// </summary> |
|
452 |
/// <param name="member">The member.</param> |
|
453 |
/// <param name="target">The target object.</param> |
|
454 |
/// <returns>The member's value on the object.</returns> |
|
455 |
public static object GetMemberValue(MemberInfo member, object target) |
|
456 |
{ |
|
457 |
32 |
ValidationUtils.ArgumentNotNull(member, "member");
|
458 |
32 |
ValidationUtils.ArgumentNotNull(target, "target");
|
459 |
||
460 |
32 |
switch (member.MemberType)
|
461 |
{ |
|
462 |
case MemberTypes.Field: |
|
463 |
7 |
return ((FieldInfo)member).GetValue(target);
|
464 |
case MemberTypes.Property: |
|
465 |
try |
|
466 |
{ |
|
467 |
25 |
return ((PropertyInfo)member).GetValue(target, null);
|
468 |
} |
|
469 |
0 |
catch (TargetParameterCountException e)
|
470 |
{ |
|
471 |
0 |
throw new ArgumentException("MemberInfo '{0}' has index parameters".FormatWith(CultureInfo.InvariantCulture, member.Name), e);
|
472 |
} |
|
473 |
default: |
|
474 |
0 |
throw new ArgumentException("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo".FormatWith(CultureInfo.InvariantCulture, CultureInfo.InvariantCulture, member.Name), "member");
|
475 |
} |
|
476 |
32 |
}
|
477 |
||
478 |
/// <summary> |
|
479 |
/// Sets the member's value on the target object. |
|
480 |
/// </summary> |
|
481 |
/// <param name="member">The member.</param> |
|
482 |
/// <param name="target">The target.</param> |
|
483 |
/// <param name="value">The value.</param> |
|
484 |
public static void SetMemberValue(MemberInfo member, object target, object value) |
|
485 |
{ |
|
486 |
0 |
ValidationUtils.ArgumentNotNull(member, "member");
|
487 |
0 |
ValidationUtils.ArgumentNotNull(target, "target");
|
488 |
||
489 |
0 |
switch (member.MemberType)
|
490 |
{ |
|
491 |
case MemberTypes.Field: |
|
492 |
0 |
((FieldInfo)member).SetValue(target, value);
|
493 |
0 |
break;
|
494 |
case MemberTypes.Property: |
|
495 |
0 |
((PropertyInfo)member).SetValue(target, value, null);
|
496 |
0 |
break;
|
497 |
default: |
|
498 |
0 |
throw new ArgumentException("MemberInfo '{0}' must be of type FieldInfo or PropertyInfo".FormatWith(CultureInfo.InvariantCulture, member.Name), "member");
|
499 |
} |
|
500 |
0 |
}
|
501 |
||
502 |
/// <summary> |
|
503 |
/// Determines whether the specified MemberInfo can be read. |
|
504 |
/// </summary> |
|
505 |
/// <param name="member">The MemberInfo to determine whether can be read.</param> |
|
506 |
/// /// <param name="nonPublic">if set to <c>true</c> then allow the member to be gotten non-publicly.</param> |
|
507 |
/// <returns> |
|
508 |
/// <c>true</c> if the specified MemberInfo can be read; otherwise, <c>false</c>. |
|
509 |
/// </returns> |
|
510 |
public static bool CanReadMemberValue(MemberInfo member, bool nonPublic) |
|
511 |
{ |
|
512 |
598 |
switch (member.MemberType)
|
513 |
{ |
|
514 |
case MemberTypes.Field: |
|
515 |
128 |
FieldInfo fieldInfo = (FieldInfo)member;
|
516 |
||
517 |
128 |
if (nonPublic)
|
518 |
21 |
return true;
|
519 |
107 |
else if (fieldInfo.IsPublic)
|
520 |
107 |
return true;
|
521 |
0 |
return false;
|
522 |
case MemberTypes.Property: |
|
523 |
470 |
PropertyInfo propertyInfo = (PropertyInfo) member;
|
524 |
||
525 |
470 |
if (!propertyInfo.CanRead)
|
526 |
2 |
return false;
|
527 |
468 |
if (nonPublic)
|
528 |
93 |
return true;
|
529 |
375 |
return (propertyInfo.GetGetMethod(nonPublic) != null);
|
530 |
default: |
|
531 |
0 |
return false;
|
532 |
} |
|
533 |
598 |
}
|
534 |
||
535 |
/// <summary> |
|
536 |
/// Determines whether the specified MemberInfo can be set. |
|
537 |
/// </summary> |
|
538 |
/// <param name="member">The MemberInfo to determine whether can be set.</param> |
|
539 |
/// <param name="nonPublic">if set to <c>true</c> then allow the member to be set non-publicly.</param> |
|
540 |
/// <returns> |
|
541 |
/// <c>true</c> if the specified MemberInfo can be set; otherwise, <c>false</c>. |
|
542 |
/// </returns> |
|
543 |
public static bool CanSetMemberValue(MemberInfo member, bool nonPublic) |
|
544 |
{ |
|
545 |
598 |
switch (member.MemberType)
|
546 |
{ |
|
547 |
case MemberTypes.Field: |
|
548 |
128 |
FieldInfo fieldInfo = (FieldInfo)member;
|
549 |
||
550 |
128 |
if (fieldInfo.IsInitOnly)
|
551 |
3 |
return false;
|
552 |
125 |
if (nonPublic)
|
553 |
20 |
return true;
|
554 |
105 |
else if (fieldInfo.IsPublic)
|
555 |
105 |
return true;
|
556 |
0 |
return false;
|
557 |
case MemberTypes.Property: |
|
558 |
470 |
PropertyInfo propertyInfo = (PropertyInfo)member;
|
559 |
||
560 |
470 |
if (!propertyInfo.CanWrite)
|
561 |
99 |
return false;
|
562 |
371 |
if (nonPublic)
|
563 |
88 |
return true;
|
564 |
283 |
return (propertyInfo.GetSetMethod(nonPublic) != null);
|
565 |
default: |
|
566 |
0 |
return false;
|
567 |
} |
|
568 |
598 |
}
|
569 |
||
570 |
public static List<MemberInfo> GetFieldsAndProperties<T>(BindingFlags bindingAttr) |
|
571 |
{ |
|
572 |
0 |
return GetFieldsAndProperties(typeof(T), bindingAttr);
|
573 |
0 |
}
|
574 |
||
575 |
public static List<MemberInfo> GetFieldsAndProperties(Type type, BindingFlags bindingAttr) |
|
576 |
{ |
|
577 |
346 |
List<MemberInfo> targetMembers = new List<MemberInfo>();
|
578 |
||
579 |
346 |
targetMembers.AddRange(GetFields(type, bindingAttr));
|
580 |
346 |
targetMembers.AddRange(GetProperties(type, bindingAttr));
|
581 |
||
582 |
// for some reason .NET returns multiple members when overriding a generic member on a base class |
|
583 |
// http://forums.msdn.microsoft.com/en-US/netfxbcl/thread/b5abbfee-e292-4a64-8907-4e3f0fb90cd9/ |
|
584 |
// filter members to only return the override on the topmost class |
|
585 |
// update: I think this is fixed in .NET 3.5 SP1 - leave this in for now... |
|
586 |
346 |
List<MemberInfo> distinctMembers = new List<MemberInfo>(targetMembers.Count);
|
587 |
||
588 |
346 |
var groupedMembers = targetMembers.GroupBy(m => m.Name).Select(g => new { Count = g.Count(), Members = g.Cast<MemberInfo>() });
|
589 |
346 |
foreach (var groupedMember in groupedMembers)
|
590 |
{ |
|
591 |
1723 |
if (groupedMember.Count == 1)
|
592 |
{ |
|
593 |
1721 |
distinctMembers.Add(groupedMember.Members.First());
|
594 |
} |
|
595 |
else |
|
596 |
{ |
|
597 |
2 |
var members = groupedMember.Members.Where(m => !IsOverridenGenericMember(m, bindingAttr) || m.Name == "Item");
|
598 |
||
599 |
2 |
distinctMembers.AddRange(members);
|
600 |
} |
|
601 |
} |
|
602 |
||
603 |
346 |
return distinctMembers;
|
604 |
346 |
}
|
605 |
||
606 |
private static bool IsOverridenGenericMember(MemberInfo memberInfo, BindingFlags bindingAttr) |
|
607 |
{ |
|
608 |
4 |
if (memberInfo.MemberType != MemberTypes.Field && memberInfo.MemberType != MemberTypes.Property)
|
609 |
0 |
throw new ArgumentException("Member must be a field or property.");
|
610 |
||
611 |
4 |
Type declaringType = memberInfo.DeclaringType;
|
612 |
4 |
if (!declaringType.IsGenericType)
|
613 |
0 |
return false;
|
614 |
4 |
Type genericTypeDefinition = declaringType.GetGenericTypeDefinition();
|
615 |
4 |
if (genericTypeDefinition == null)
|
616 |
0 |
return false;
|
617 |
4 |
MemberInfo[] members = genericTypeDefinition.GetMember(memberInfo.Name, bindingAttr);
|
618 |
4 |
if (members.Length == 0)
|
619 |
0 |
return false;
|
620 |
4 |
Type memberUnderlyingType = GetMemberUnderlyingType(members[0]);
|
621 |
4 |
if (!memberUnderlyingType.IsGenericParameter)
|
622 |
0 |
return false;
|
623 |
||
624 |
4 |
return true;
|
625 |
4 |
}
|
626 |
||
627 |
public static T GetAttribute<T>(ICustomAttributeProvider attributeProvider) where T : Attribute |
|
628 |
{ |
|
629 |
257 |
return GetAttribute<T>(attributeProvider, true);
|
630 |
257 |
}
|
631 |
||
632 |
public static T GetAttribute<T>(ICustomAttributeProvider attributeProvider, bool inherit) where T : Attribute |
|
633 |
{ |
|
634 |
4218 |
T[] attributes = GetAttributes<T>(attributeProvider, inherit);
|
635 |
||
636 |
4218 |
return CollectionUtils.GetSingleItem(attributes, true);
|
637 |
4218 |
}
|
638 |
||
639 |
public static T[] GetAttributes<T>(ICustomAttributeProvider attributeProvider, bool inherit) where T : Attribute |
|
640 |
{ |
|
641 |
4218 |
ValidationUtils.ArgumentNotNull(attributeProvider, "attributeProvider");
|
642 |
||
643 |
4218 |
return (T[])attributeProvider.GetCustomAttributes(typeof(T), inherit);
|
644 |
4218 |
}
|
645 |
||
646 |
public static string GetNameAndAssessmblyName(Type t) |
|
647 |
{ |
|
648 |
0 |
ValidationUtils.ArgumentNotNull(t, "t");
|
649 |
||
650 |
0 |
return t.FullName + ", " + t.Assembly.GetName().Name;
|
651 |
0 |
}
|
652 |
||
653 |
public static Type MakeGenericType(Type genericTypeDefinition, params Type[] innerTypes) |
|
654 |
{ |
|
655 |
12 |
ValidationUtils.ArgumentNotNull(genericTypeDefinition, "genericTypeDefinition");
|
656 |
12 |
ValidationUtils.ArgumentNotNullOrEmpty<Type>(innerTypes, "innerTypes");
|
657 |
12 |
ValidationUtils.ArgumentConditionTrue(genericTypeDefinition.IsGenericTypeDefinition, "genericTypeDefinition", "Type {0} is not a generic type definition.".FormatWith(CultureInfo.InvariantCulture, genericTypeDefinition));
|
658 |
||
659 |
12 |
return genericTypeDefinition.MakeGenericType(innerTypes);
|
660 |
12 |
}
|
661 |
||
662 |
public static object CreateGeneric(Type genericTypeDefinition, Type innerType, params object[] args) |
|
663 |
{ |
|
664 |
1 |
return CreateGeneric(genericTypeDefinition, new [] { innerType }, args);
|
665 |
1 |
}
|
666 |
||
667 |
public static object CreateGeneric(Type genericTypeDefinition, IList<Type> innerTypes, params object[] args) |
|
668 |
{ |
|
669 |
1 |
return CreateGeneric(genericTypeDefinition, innerTypes, (t, a) => CreateInstance(t, a.ToArray()), args);
|
670 |
1 |
}
|
671 |
||
672 |
public static object CreateGeneric(Type genericTypeDefinition, IList<Type> innerTypes, Func<Type, IList<object>, object> instanceCreator, params object[] args) |
|
673 |
{ |
|
674 |
4 |
ValidationUtils.ArgumentNotNull(genericTypeDefinition, "genericTypeDefinition");
|
675 |
4 |
ValidationUtils.ArgumentNotNullOrEmpty(innerTypes, "innerTypes");
|
676 |
4 |
ValidationUtils.ArgumentNotNull(instanceCreator, "createInstance");
|
677 |
||
678 |
4 |
Type specificType = MakeGenericType(genericTypeDefinition, innerTypes.ToArray());
|
679 |
||
680 |
4 |
return instanceCreator(specificType, args);
|
681 |
4 |
}
|
682 |
||
683 |
public static bool IsCompatibleValue(object value, Type type) |
|
684 |
{ |
|
685 |
0 |
if (value == null)
|
686 |
0 |
return IsNullable(type);
|
687 |
||
688 |
0 |
if (type.IsAssignableFrom(value.GetType()))
|
689 |
0 |
return true;
|
690 |
||
691 |
0 |
return false;
|
692 |
0 |
}
|
693 |
||
694 |
public static object CreateInstance(Type type, params object[] args) |
|
695 |
{ |
|
696 |
6 |
ValidationUtils.ArgumentNotNull(type, "type");
|
697 |
||
698 |
#if !PocketPC |
|
699 |
6 |
return Activator.CreateInstance(type, args);
|
700 |
#else |
|
701 |
// CF doesn't have a Activator.CreateInstance overload that takes args |
|
702 |
// lame |
|
703 |
||
704 |
if (type.IsValueType && CollectionUtils.IsNullOrEmpty<object>(args)) |
|
705 |
return Activator.CreateInstance(type); |
|
706 |
||
707 |
ConstructorInfo[] constructors = type.GetConstructors(); |
|
708 |
ConstructorInfo match = constructors.Where(c => |
|
709 |
{ |
|
710 |
ParameterInfo[] parameters = c.GetParameters(); |
|
711 |
if (parameters.Length != args.Length) |
|
712 |
return false; |
|
713 |
||
714 |
for (int i = 0; i < parameters.Length; i++) |
|
715 |
{ |
|
716 |
ParameterInfo parameter = parameters[i]; |
|
717 |
object value = args[i]; |
|
718 |
||
719 |
if (!IsCompatibleValue(value, parameter.ParameterType)) |
|
720 |
return false; |
|
721 |
} |
|
722 |
||
723 |
return true; |
|
724 |
}).FirstOrDefault(); |
|
725 |
||
726 |
if (match == null) |
|
727 |
throw new Exception("Could not create '{0}' with given parameters.".FormatWith(CultureInfo.InvariantCulture, type)); |
|
728 |
||
729 |
return match.Invoke(args); |
|
730 |
#endif |
|
731 |
6 |
}
|
732 |
||
733 |
public static void SplitFullyQualifiedTypeName(string fullyQualifiedTypeName, out string typeName, out string assemblyName) |
|
734 |
{ |
|
735 |
13 |
int? assemblyDelimiterIndex = GetAssemblyDelimiterIndex(fullyQualifiedTypeName);
|
736 |
||
737 |
13 |
if (assemblyDelimiterIndex != null)
|
738 |
{ |
|
739 |
12 |
typeName = fullyQualifiedTypeName.Substring(0, assemblyDelimiterIndex.Value).Trim();
|
740 |
12 |
assemblyName = fullyQualifiedTypeName.Substring(assemblyDelimiterIndex.Value + 1, fullyQualifiedTypeName.Length - assemblyDelimiterIndex.Value - 1).Trim();
|
741 |
} |
|
742 |
else |
|
743 |
{ |
|
744 |
1 |
typeName = fullyQualifiedTypeName;
|
745 |
1 |
assemblyName = null;
|
746 |
} |
|
747 |
||
748 |
13 |
}
|
749 |
||
750 |
private static int? GetAssemblyDelimiterIndex(string fullyQualifiedTypeName) |
|
751 |
{ |
|
752 |
// we need to get the first comma following all surrounded in brackets because of generic types |
|
753 |
// e.g. System.Collections.Generic.Dictionary`2[[System.String, mscorlib,Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 |
|
754 |
13 |
int scope = 0;
|
755 |
13 |
for (int i = 0; i < fullyQualifiedTypeName.Length; i++) |
756 |
{ |
|
757 |
957 |
char current = fullyQualifiedTypeName[i];
|
758 |
957 |
switch (current)
|
759 |
{ |
|
760 |
case '[': |
|
761 |
5 |
scope++;
|
762 |
5 |
break;
|
763 |
case ']': |
|
764 |
5 |
scope--;
|
765 |
5 |
break;
|
766 |
case ',': |
|
767 |
25 |
if (scope == 0)
|
768 |
12 |
return i;
|
769 |
13 |
break;
|
770 |
} |
|
771 |
} |
|
772 |
||
773 |
1 |
return null;
|
774 |
13 |
}
|
775 |
||
776 |
public static IEnumerable<FieldInfo> GetFields(Type targetType, BindingFlags bindingAttr) |
|
777 |
{ |
|
778 |
346 |
ValidationUtils.ArgumentNotNull(targetType, "targetType");
|
779 |
||
780 |
346 |
List<MemberInfo> fieldInfos = new List<MemberInfo>(targetType.GetFields(bindingAttr));
|
781 |
// Type.GetFields doesn't return inherited private fields |
|
782 |
// manually find private fields from base class |
|
783 |
346 |
GetChildPrivateFields(fieldInfos, targetType, bindingAttr);
|
784 |
||
785 |
346 |
return fieldInfos.Cast<FieldInfo>();
|
786 |
346 |
}
|
787 |
||
788 |
private static void GetChildPrivateFields(IList<MemberInfo> initialFields, Type targetType, BindingFlags bindingAttr) |
|
789 |
{ |
|
790 |
// fix weirdness with private FieldInfos only being returned for the current Type |
|
791 |
// find base type fields and add them to result |
|
792 |
346 |
if ((bindingAttr & BindingFlags.NonPublic) != 0)
|
793 |
{ |
|
794 |
// modify flags to not search for public fields |
|
795 |
174 |
BindingFlags nonPublicBindingAttr = bindingAttr.RemoveFlag(BindingFlags.Public);
|
796 |
||
797 |
376 |
while ((targetType = targetType.BaseType) != null)
|
798 |
{ |
|
799 |
// filter out protected fields |
|
800 |
202 |
IEnumerable<MemberInfo> childPrivateFields =
|
801 |
63 |
targetType.GetFields(nonPublicBindingAttr).Where(f => f.IsPrivate).Cast<MemberInfo>();
|
802 |
||
803 |
202 |
initialFields.AddRange(childPrivateFields);
|
804 |
} |
|
805 |
} |
|
806 |
346 |
}
|
807 |
||
808 |
public static IEnumerable<PropertyInfo> GetProperties(Type targetType, BindingFlags bindingAttr) |
|
809 |
{ |
|
810 |
346 |
ValidationUtils.ArgumentNotNull(targetType, "targetType");
|
811 |
||
812 |
346 |
List<MemberInfo> propertyInfos = new List<MemberInfo>(targetType.GetProperties(bindingAttr));
|
813 |
346 |
GetChildPrivateProperties(propertyInfos, targetType, bindingAttr);
|
814 |
||
815 |
346 |
return propertyInfos.Cast<PropertyInfo>();
|
816 |
346 |
}
|
817 |
||
818 |
public static BindingFlags RemoveFlag(this BindingFlags bindingAttr, BindingFlags flag) |
|
819 |
{ |
|
820 |
348 |
return ((bindingAttr & flag) == flag)
|
821 |
348 |
? bindingAttr ^ flag
|
822 |
348 |
: bindingAttr;
|
823 |
348 |
}
|
824 |
||
825 |
private static void GetChildPrivateProperties(IList<MemberInfo> initialProperties, Type targetType, BindingFlags bindingAttr) |
|
826 |
{ |
|
827 |
// fix weirdness with private PropertyInfos only being returned for the current Type |
|
828 |
// find base type properties and add them to result |
|
829 |
346 |
if ((bindingAttr & BindingFlags.NonPublic) != 0)
|
830 |
{ |
|
831 |
// modify flags to not search for public fields |
|
832 |
174 |
BindingFlags nonPublicBindingAttr = bindingAttr.RemoveFlag(BindingFlags.Public);
|
833 |
||
834 |
376 |
while ((targetType = targetType.BaseType) != null)
|
835 |
{ |
|
836 |
30 |
foreach (PropertyInfo propertyInfo in targetType.GetProperties(nonPublicBindingAttr))
|
837 |
{ |
|
838 |
30 |
PropertyInfo nonPublicProperty = propertyInfo;
|
839 |
||
840 |
// have to test on name rather than reference because instances are different |
|
841 |
// depending on the type that GetProperties was called on |
|
842 |
30 |
int index = initialProperties.IndexOf(p => p.Name == nonPublicProperty.Name);
|
843 |
30 |
if (index == -1)
|
844 |
{ |
|
845 |
14 |
initialProperties.Add(nonPublicProperty);
|
846 |
} |
|
847 |
else |
|
848 |
{ |
|
849 |
// replace nonpublic properties for a child, but gotten from |
|
850 |
// the parent with the one from the child |
|
851 |
// the property gotten from the child will have access to private getter/setter |
|
852 |
16 |
initialProperties[index] = nonPublicProperty;
|
853 |
} |
|
854 |
} |
|
855 |
} |
|
856 |
} |
|
857 |
346 |
}
|
858 |
} |
|
859 |
} |