You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1139 lines
42 KiB

  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. using System;
  26. using System.Collections.Generic;
  27. #if HAVE_BIG_INTEGER
  28. using System.Numerics;
  29. #endif
  30. using System.Reflection;
  31. using System.Collections;
  32. using System.Globalization;
  33. using System.Text;
  34. #if NET20
  35. using Newtonsoft.Json.Utilities.LinqBridge;
  36. #else
  37. using System.Linq;
  38. #endif
  39. using Newtonsoft.Json.Serialization;
  40. namespace Newtonsoft.Json.Utilities
  41. {
  42. #if (DOTNET || PORTABLE || PORTABLE40) && !NETSTD
  43. [Flags]
  44. internal enum MemberTypes
  45. {
  46. Event = 2,
  47. Field = 4,
  48. Method = 8,
  49. Property = 16
  50. }
  51. #endif
  52. #if PORTABLE && !NETSTD
  53. [Flags]
  54. internal enum BindingFlags
  55. {
  56. Default = 0,
  57. IgnoreCase = 1,
  58. DeclaredOnly = 2,
  59. Instance = 4,
  60. Static = 8,
  61. Public = 16,
  62. NonPublic = 32,
  63. FlattenHierarchy = 64,
  64. InvokeMethod = 256,
  65. CreateInstance = 512,
  66. GetField = 1024,
  67. SetField = 2048,
  68. GetProperty = 4096,
  69. SetProperty = 8192,
  70. PutDispProperty = 16384,
  71. ExactBinding = 65536,
  72. PutRefDispProperty = 32768,
  73. SuppressChangeType = 131072,
  74. OptionalParamBinding = 262144,
  75. IgnoreReturn = 16777216
  76. }
  77. #endif
  78. internal static class ReflectionUtils
  79. {
  80. public static readonly Type[] EmptyTypes;
  81. static ReflectionUtils()
  82. {
  83. EmptyTypes = Type.EmptyTypes;
  84. // EmptyTypes = CollectionUtils.ArrayEmpty<Type>();
  85. }
  86. public static bool IsVirtual(this PropertyInfo propertyInfo)
  87. {
  88. ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
  89. MethodInfo m = propertyInfo.GetGetMethod(true);
  90. if (m != null && m.IsVirtual)
  91. {
  92. return true;
  93. }
  94. m = propertyInfo.GetSetMethod(true);
  95. if (m != null && m.IsVirtual)
  96. {
  97. return true;
  98. }
  99. return false;
  100. }
  101. public static MethodInfo GetBaseDefinition(this PropertyInfo propertyInfo)
  102. {
  103. ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
  104. MethodInfo m = propertyInfo.GetGetMethod(true);
  105. if (m != null)
  106. {
  107. return m.GetBaseDefinition();
  108. }
  109. return propertyInfo.GetSetMethod(true)?.GetBaseDefinition();
  110. }
  111. public static bool IsPublic(PropertyInfo property)
  112. {
  113. if (property.GetGetMethod() != null && property.GetGetMethod().IsPublic)
  114. {
  115. return true;
  116. }
  117. if (property.GetSetMethod() != null && property.GetSetMethod().IsPublic)
  118. {
  119. return true;
  120. }
  121. return false;
  122. }
  123. public static Type GetObjectType(object v)
  124. {
  125. return v?.GetType();
  126. }
  127. public static string GetTypeName(Type t, TypeNameAssemblyFormatHandling assemblyFormat, ISerializationBinder binder)
  128. {
  129. string fullyQualifiedTypeName = GetFullyQualifiedTypeName(t, binder);
  130. switch (assemblyFormat)
  131. {
  132. case TypeNameAssemblyFormatHandling.Simple:
  133. return RemoveAssemblyDetails(fullyQualifiedTypeName);
  134. case TypeNameAssemblyFormatHandling.Full:
  135. return fullyQualifiedTypeName;
  136. default:
  137. throw new ArgumentOutOfRangeException();
  138. }
  139. }
  140. private static string GetFullyQualifiedTypeName(Type t, ISerializationBinder binder)
  141. {
  142. if (binder != null)
  143. {
  144. binder.BindToName(t, out string assemblyName, out string typeName);
  145. #if (NET20 || NET35)
  146. // for older SerializationBinder implementations that didn't have BindToName
  147. if (assemblyName == null & typeName == null)
  148. {
  149. return t.AssemblyQualifiedName;
  150. }
  151. #endif
  152. return typeName + (assemblyName == null ? "" : ", " + assemblyName);
  153. }
  154. return t.AssemblyQualifiedName;
  155. }
  156. private static string RemoveAssemblyDetails(string fullyQualifiedTypeName)
  157. {
  158. StringBuilder builder = new StringBuilder();
  159. // loop through the type name and filter out qualified assembly details from nested type names
  160. bool writingAssemblyName = false;
  161. bool skippingAssemblyDetails = false;
  162. for (int i = 0; i < fullyQualifiedTypeName.Length; i++)
  163. {
  164. char current = fullyQualifiedTypeName[i];
  165. switch (current)
  166. {
  167. case '[':
  168. writingAssemblyName = false;
  169. skippingAssemblyDetails = false;
  170. builder.Append(current);
  171. break;
  172. case ']':
  173. writingAssemblyName = false;
  174. skippingAssemblyDetails = false;
  175. builder.Append(current);
  176. break;
  177. case ',':
  178. if (!writingAssemblyName)
  179. {
  180. writingAssemblyName = true;
  181. builder.Append(current);
  182. }
  183. else
  184. {
  185. skippingAssemblyDetails = true;
  186. }
  187. break;
  188. default:
  189. if (!skippingAssemblyDetails)
  190. {
  191. builder.Append(current);
  192. }
  193. break;
  194. }
  195. }
  196. return builder.ToString();
  197. }
  198. public static bool HasDefaultConstructor(Type t, bool nonPublic)
  199. {
  200. ValidationUtils.ArgumentNotNull(t, nameof(t));
  201. if (t.IsValueType())
  202. {
  203. return true;
  204. }
  205. return (GetDefaultConstructor(t, nonPublic) != null);
  206. }
  207. public static ConstructorInfo GetDefaultConstructor(Type t)
  208. {
  209. return GetDefaultConstructor(t, false);
  210. }
  211. public static ConstructorInfo GetDefaultConstructor(Type t, bool nonPublic)
  212. {
  213. BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public;
  214. if (nonPublic)
  215. {
  216. bindingFlags = bindingFlags | BindingFlags.NonPublic;
  217. }
  218. return t.GetConstructors(bindingFlags).SingleOrDefault(c => !c.GetParameters().Any());
  219. }
  220. public static bool IsNullable(Type t)
  221. {
  222. ValidationUtils.ArgumentNotNull(t, nameof(t));
  223. if (t.IsValueType())
  224. {
  225. return IsNullableType(t);
  226. }
  227. return true;
  228. }
  229. public static bool IsNullableType(Type t)
  230. {
  231. ValidationUtils.ArgumentNotNull(t, nameof(t));
  232. return (t.IsGenericType() && t.GetGenericTypeDefinition() == typeof(Nullable<>));
  233. }
  234. public static Type EnsureNotNullableType(Type t)
  235. {
  236. return (IsNullableType(t))
  237. ? Nullable.GetUnderlyingType(t)
  238. : t;
  239. }
  240. public static bool IsGenericDefinition(Type type, Type genericInterfaceDefinition)
  241. {
  242. if (!type.IsGenericType())
  243. {
  244. return false;
  245. }
  246. Type t = type.GetGenericTypeDefinition();
  247. return (t == genericInterfaceDefinition);
  248. }
  249. public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition)
  250. {
  251. return ImplementsGenericDefinition(type, genericInterfaceDefinition, out _);
  252. }
  253. public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition, out Type implementingType)
  254. {
  255. ValidationUtils.ArgumentNotNull(type, nameof(type));
  256. ValidationUtils.ArgumentNotNull(genericInterfaceDefinition, nameof(genericInterfaceDefinition));
  257. if (!genericInterfaceDefinition.IsInterface() || !genericInterfaceDefinition.IsGenericTypeDefinition())
  258. {
  259. throw new ArgumentNullException("'{0}' is not a generic interface definition.".FormatWith(CultureInfo.InvariantCulture, genericInterfaceDefinition));
  260. }
  261. if (type.IsInterface())
  262. {
  263. if (type.IsGenericType())
  264. {
  265. Type interfaceDefinition = type.GetGenericTypeDefinition();
  266. if (genericInterfaceDefinition == interfaceDefinition)
  267. {
  268. implementingType = type;
  269. return true;
  270. }
  271. }
  272. }
  273. foreach (Type i in type.GetInterfaces())
  274. {
  275. if (i.IsGenericType())
  276. {
  277. Type interfaceDefinition = i.GetGenericTypeDefinition();
  278. if (genericInterfaceDefinition == interfaceDefinition)
  279. {
  280. implementingType = i;
  281. return true;
  282. }
  283. }
  284. }
  285. implementingType = null;
  286. return false;
  287. }
  288. public static bool InheritsGenericDefinition(Type type, Type genericClassDefinition)
  289. {
  290. return InheritsGenericDefinition(type, genericClassDefinition, out _);
  291. }
  292. public static bool InheritsGenericDefinition(Type type, Type genericClassDefinition, out Type implementingType)
  293. {
  294. ValidationUtils.ArgumentNotNull(type, nameof(type));
  295. ValidationUtils.ArgumentNotNull(genericClassDefinition, nameof(genericClassDefinition));
  296. if (!genericClassDefinition.IsClass() || !genericClassDefinition.IsGenericTypeDefinition())
  297. {
  298. throw new ArgumentNullException("'{0}' is not a generic class definition.".FormatWith(CultureInfo.InvariantCulture, genericClassDefinition));
  299. }
  300. return InheritsGenericDefinitionInternal(type, genericClassDefinition, out implementingType);
  301. }
  302. private static bool InheritsGenericDefinitionInternal(Type currentType, Type genericClassDefinition, out Type implementingType)
  303. {
  304. do
  305. {
  306. if (currentType.IsGenericType() && genericClassDefinition == currentType.GetGenericTypeDefinition())
  307. {
  308. implementingType = currentType;
  309. return true;
  310. }
  311. currentType = currentType.BaseType();
  312. }
  313. while (currentType != null);
  314. implementingType = null;
  315. return false;
  316. }
  317. /// <summary>
  318. /// Gets the type of the typed collection's items.
  319. /// </summary>
  320. /// <param name="type">The type.</param>
  321. /// <returns>The type of the typed collection's items.</returns>
  322. public static Type GetCollectionItemType(Type type)
  323. {
  324. ValidationUtils.ArgumentNotNull(type, nameof(type));
  325. if (type.IsArray)
  326. {
  327. return type.GetElementType();
  328. }
  329. if (ImplementsGenericDefinition(type, typeof(IEnumerable<>), out Type genericListType))
  330. {
  331. if (genericListType.IsGenericTypeDefinition())
  332. {
  333. throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
  334. }
  335. return genericListType.GetGenericArguments()[0];
  336. }
  337. if (typeof(IEnumerable).IsAssignableFrom(type))
  338. {
  339. return null;
  340. }
  341. throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
  342. }
  343. public static void GetDictionaryKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType)
  344. {
  345. ValidationUtils.ArgumentNotNull(dictionaryType, nameof(dictionaryType));
  346. if (ImplementsGenericDefinition(dictionaryType, typeof(IDictionary<,>), out Type genericDictionaryType))
  347. {
  348. if (genericDictionaryType.IsGenericTypeDefinition())
  349. {
  350. throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType));
  351. }
  352. Type[] dictionaryGenericArguments = genericDictionaryType.GetGenericArguments();
  353. keyType = dictionaryGenericArguments[0];
  354. valueType = dictionaryGenericArguments[1];
  355. return;
  356. }
  357. if (typeof(IDictionary).IsAssignableFrom(dictionaryType))
  358. {
  359. keyType = null;
  360. valueType = null;
  361. return;
  362. }
  363. throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType));
  364. }
  365. /// <summary>
  366. /// Gets the member's underlying type.
  367. /// </summary>
  368. /// <param name="member">The member.</param>
  369. /// <returns>The underlying type of the member.</returns>
  370. public static Type GetMemberUnderlyingType(MemberInfo member)
  371. {
  372. ValidationUtils.ArgumentNotNull(member, nameof(member));
  373. switch (member.MemberType())
  374. {
  375. case MemberTypes.Field:
  376. return ((FieldInfo)member).FieldType;
  377. case MemberTypes.Property:
  378. return ((PropertyInfo)member).PropertyType;
  379. case MemberTypes.Event:
  380. return ((EventInfo)member).EventHandlerType;
  381. case MemberTypes.Method:
  382. return ((MethodInfo)member).ReturnType;
  383. default:
  384. throw new ArgumentException("MemberInfo must be of type FieldInfo, PropertyInfo, EventInfo or MethodInfo", nameof(member));
  385. }
  386. }
  387. /// <summary>
  388. /// Determines whether the member is an indexed property.
  389. /// </summary>
  390. /// <param name="member">The member.</param>
  391. /// <returns>
  392. /// <c>true</c> if the member is an indexed property; otherwise, <c>false</c>.
  393. /// </returns>
  394. public static bool IsIndexedProperty(MemberInfo member)
  395. {
  396. ValidationUtils.ArgumentNotNull(member, nameof(member));
  397. if (member is PropertyInfo propertyInfo)
  398. {
  399. return IsIndexedProperty(propertyInfo);
  400. }
  401. else
  402. {
  403. return false;
  404. }
  405. }
  406. /// <summary>
  407. /// Determines whether the property is an indexed property.
  408. /// </summary>
  409. /// <param name="property">The property.</param>
  410. /// <returns>
  411. /// <c>true</c> if the property is an indexed property; otherwise, <c>false</c>.
  412. /// </returns>
  413. public static bool IsIndexedProperty(PropertyInfo property)
  414. {
  415. ValidationUtils.ArgumentNotNull(property, nameof(property));
  416. return (property.GetIndexParameters().Length > 0);
  417. }
  418. /// <summary>
  419. /// Gets the member's value on the object.
  420. /// </summary>
  421. /// <param name="member">The member.</param>
  422. /// <param name="target">The target object.</param>
  423. /// <returns>The member's value on the object.</returns>
  424. public static object GetMemberValue(MemberInfo member, object target)
  425. {
  426. ValidationUtils.ArgumentNotNull(member, nameof(member));
  427. ValidationUtils.ArgumentNotNull(target, nameof(target));
  428. switch (member.MemberType())
  429. {
  430. case MemberTypes.Field:
  431. return ((FieldInfo)member).GetValue(target);
  432. case MemberTypes.Property:
  433. try
  434. {
  435. return ((PropertyInfo)member).GetValue(target, null);
  436. }
  437. catch (TargetParameterCountException e)
  438. {
  439. throw new ArgumentException("MemberInfo '{0}' has index parameters".FormatWith(CultureInfo.InvariantCulture, member.Name), e);
  440. }
  441. default:
  442. throw new ArgumentException("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo".FormatWith(CultureInfo.InvariantCulture, member.Name), nameof(member));
  443. }
  444. }
  445. /// <summary>
  446. /// Sets the member's value on the target object.
  447. /// </summary>
  448. /// <param name="member">The member.</param>
  449. /// <param name="target">The target.</param>
  450. /// <param name="value">The value.</param>
  451. public static void SetMemberValue(MemberInfo member, object target, object value)
  452. {
  453. ValidationUtils.ArgumentNotNull(member, nameof(member));
  454. ValidationUtils.ArgumentNotNull(target, nameof(target));
  455. switch (member.MemberType())
  456. {
  457. case MemberTypes.Field:
  458. ((FieldInfo)member).SetValue(target, value);
  459. break;
  460. case MemberTypes.Property:
  461. ((PropertyInfo)member).SetValue(target, value, null);
  462. break;
  463. default:
  464. throw new ArgumentException("MemberInfo '{0}' must be of type FieldInfo or PropertyInfo".FormatWith(CultureInfo.InvariantCulture, member.Name), nameof(member));
  465. }
  466. }
  467. /// <summary>
  468. /// Determines whether the specified MemberInfo can be read.
  469. /// </summary>
  470. /// <param name="member">The MemberInfo to determine whether can be read.</param>
  471. /// /// <param name="nonPublic">if set to <c>true</c> then allow the member to be gotten non-publicly.</param>
  472. /// <returns>
  473. /// <c>true</c> if the specified MemberInfo can be read; otherwise, <c>false</c>.
  474. /// </returns>
  475. public static bool CanReadMemberValue(MemberInfo member, bool nonPublic)
  476. {
  477. switch (member.MemberType())
  478. {
  479. case MemberTypes.Field:
  480. FieldInfo fieldInfo = (FieldInfo)member;
  481. if (nonPublic)
  482. {
  483. return true;
  484. }
  485. else if (fieldInfo.IsPublic)
  486. {
  487. return true;
  488. }
  489. return false;
  490. case MemberTypes.Property:
  491. PropertyInfo propertyInfo = (PropertyInfo)member;
  492. if (!propertyInfo.CanRead)
  493. {
  494. return false;
  495. }
  496. if (nonPublic)
  497. {
  498. return true;
  499. }
  500. return (propertyInfo.GetGetMethod(nonPublic) != null);
  501. default:
  502. return false;
  503. }
  504. }
  505. /// <summary>
  506. /// Determines whether the specified MemberInfo can be set.
  507. /// </summary>
  508. /// <param name="member">The MemberInfo to determine whether can be set.</param>
  509. /// <param name="nonPublic">if set to <c>true</c> then allow the member to be set non-publicly.</param>
  510. /// <param name="canSetReadOnly">if set to <c>true</c> then allow the member to be set if read-only.</param>
  511. /// <returns>
  512. /// <c>true</c> if the specified MemberInfo can be set; otherwise, <c>false</c>.
  513. /// </returns>
  514. public static bool CanSetMemberValue(MemberInfo member, bool nonPublic, bool canSetReadOnly)
  515. {
  516. switch (member.MemberType())
  517. {
  518. case MemberTypes.Field:
  519. FieldInfo fieldInfo = (FieldInfo)member;
  520. if (fieldInfo.IsLiteral)
  521. {
  522. return false;
  523. }
  524. if (fieldInfo.IsInitOnly && !canSetReadOnly)
  525. {
  526. return false;
  527. }
  528. if (nonPublic)
  529. {
  530. return true;
  531. }
  532. if (fieldInfo.IsPublic)
  533. {
  534. return true;
  535. }
  536. return false;
  537. case MemberTypes.Property:
  538. PropertyInfo propertyInfo = (PropertyInfo)member;
  539. if (!propertyInfo.CanWrite)
  540. {
  541. return false;
  542. }
  543. if (nonPublic)
  544. {
  545. return true;
  546. }
  547. return (propertyInfo.GetSetMethod(nonPublic) != null);
  548. default:
  549. return false;
  550. }
  551. }
  552. public static List<MemberInfo> GetFieldsAndProperties(Type type, BindingFlags bindingAttr)
  553. {
  554. List<MemberInfo> targetMembers = new List<MemberInfo>();
  555. targetMembers.AddRange(GetFields(type, bindingAttr));
  556. targetMembers.AddRange(GetProperties(type, bindingAttr));
  557. // for some reason .NET returns multiple members when overriding a generic member on a base class
  558. // http://social.msdn.microsoft.com/Forums/en-US/b5abbfee-e292-4a64-8907-4e3f0fb90cd9/reflection-overriden-abstract-generic-properties?forum=netfxbcl
  559. // filter members to only return the override on the topmost class
  560. // update: I think this is fixed in .NET 3.5 SP1 - leave this in for now...
  561. List<MemberInfo> distinctMembers = new List<MemberInfo>(targetMembers.Count);
  562. foreach (IGrouping<string, MemberInfo> groupedMember in targetMembers.GroupBy(m => m.Name))
  563. {
  564. int count = groupedMember.Count();
  565. if (count == 1)
  566. {
  567. distinctMembers.Add(groupedMember.First());
  568. }
  569. else
  570. {
  571. IList<MemberInfo> resolvedMembers = new List<MemberInfo>();
  572. foreach (MemberInfo memberInfo in groupedMember)
  573. {
  574. // this is a bit hacky
  575. // if the hiding property is hiding a base property and it is virtual
  576. // then this ensures the derived property gets used
  577. if (resolvedMembers.Count == 0)
  578. {
  579. resolvedMembers.Add(memberInfo);
  580. }
  581. else if (!IsOverridenGenericMember(memberInfo, bindingAttr) || memberInfo.Name == "Item")
  582. {
  583. resolvedMembers.Add(memberInfo);
  584. }
  585. }
  586. distinctMembers.AddRange(resolvedMembers);
  587. }
  588. }
  589. return distinctMembers;
  590. }
  591. private static bool IsOverridenGenericMember(MemberInfo memberInfo, BindingFlags bindingAttr)
  592. {
  593. if (memberInfo.MemberType() != MemberTypes.Property)
  594. {
  595. return false;
  596. }
  597. PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
  598. if (!IsVirtual(propertyInfo))
  599. {
  600. return false;
  601. }
  602. Type declaringType = propertyInfo.DeclaringType;
  603. if (!declaringType.IsGenericType())
  604. {
  605. return false;
  606. }
  607. Type genericTypeDefinition = declaringType.GetGenericTypeDefinition();
  608. if (genericTypeDefinition == null)
  609. {
  610. return false;
  611. }
  612. MemberInfo[] members = genericTypeDefinition.GetMember(propertyInfo.Name, bindingAttr);
  613. if (members.Length == 0)
  614. {
  615. return false;
  616. }
  617. Type memberUnderlyingType = GetMemberUnderlyingType(members[0]);
  618. if (!memberUnderlyingType.IsGenericParameter)
  619. {
  620. return false;
  621. }
  622. return true;
  623. }
  624. public static T GetAttribute<T>(object attributeProvider) where T : Attribute
  625. {
  626. return GetAttribute<T>(attributeProvider, true);
  627. }
  628. public static T GetAttribute<T>(object attributeProvider, bool inherit) where T : Attribute
  629. {
  630. T[] attributes = GetAttributes<T>(attributeProvider, inherit);
  631. return attributes?.FirstOrDefault();
  632. }
  633. #if !(DOTNET || PORTABLE) || NETSTD
  634. public static T[] GetAttributes<T>(object attributeProvider, bool inherit) where T : Attribute
  635. {
  636. Attribute[] a = GetAttributes(attributeProvider, typeof(T), inherit);
  637. T[] attributes = a as T[];
  638. if (attributes != null)
  639. {
  640. return attributes;
  641. }
  642. return a.Cast<T>().ToArray();
  643. }
  644. public static Attribute[] GetAttributes(object attributeProvider, Type attributeType, bool inherit)
  645. {
  646. ValidationUtils.ArgumentNotNull(attributeProvider, nameof(attributeProvider));
  647. object provider = attributeProvider;
  648. // http://hyperthink.net/blog/getcustomattributes-gotcha/
  649. // ICustomAttributeProvider doesn't do inheritance
  650. Type t = provider as Type;
  651. if (t != null)
  652. {
  653. object[] array = attributeType != null ? t.GetCustomAttributes(attributeType, inherit) : t.GetCustomAttributes(inherit);
  654. Attribute[] attributes = array.Cast<Attribute>().ToArray();
  655. #if (NET20 || NET35)
  656. // ye olde .NET GetCustomAttributes doesn't respect the inherit argument
  657. if (inherit && t.BaseType != null)
  658. {
  659. attributes = attributes.Union(GetAttributes(t.BaseType, attributeType, inherit)).ToArray();
  660. }
  661. #endif
  662. return attributes;
  663. }
  664. Assembly a = provider as Assembly;
  665. if (a != null)
  666. {
  667. return (attributeType != null) ? Attribute.GetCustomAttributes(a, attributeType) : Attribute.GetCustomAttributes(a);
  668. }
  669. MemberInfo mi = provider as MemberInfo;
  670. if (mi != null)
  671. {
  672. return (attributeType != null) ? Attribute.GetCustomAttributes(mi, attributeType, inherit) : Attribute.GetCustomAttributes(mi, inherit);
  673. }
  674. #if !PORTABLE40
  675. Module m = provider as Module;
  676. if (m != null)
  677. {
  678. return (attributeType != null) ? Attribute.GetCustomAttributes(m, attributeType, inherit) : Attribute.GetCustomAttributes(m, inherit);
  679. }
  680. #endif
  681. ParameterInfo p = provider as ParameterInfo;
  682. if (p != null)
  683. {
  684. return (attributeType != null) ? Attribute.GetCustomAttributes(p, attributeType, inherit) : Attribute.GetCustomAttributes(p, inherit);
  685. }
  686. #if !PORTABLE40
  687. ICustomAttributeProvider customAttributeProvider = (ICustomAttributeProvider)attributeProvider;
  688. object[] result = (attributeType != null) ? customAttributeProvider.GetCustomAttributes(attributeType, inherit) : customAttributeProvider.GetCustomAttributes(inherit);
  689. return (Attribute[])result;
  690. #else
  691. throw new Exception("Cannot get attributes from '{0}'.".FormatWith(CultureInfo.InvariantCulture, provider));
  692. #endif
  693. }
  694. #else
  695. public static T[] GetAttributes<T>(object attributeProvider, bool inherit) where T : Attribute
  696. {
  697. return GetAttributes(attributeProvider, typeof(T), inherit).Cast<T>().ToArray();
  698. }
  699. public static Attribute[] GetAttributes(object provider, Type attributeType, bool inherit)
  700. {
  701. if (provider is Type t)
  702. {
  703. return (attributeType != null)
  704. ? t.GetTypeInfo().GetCustomAttributes(attributeType, inherit).ToArray()
  705. : t.GetTypeInfo().GetCustomAttributes(inherit).ToArray();
  706. }
  707. if (provider is Assembly a)
  708. {
  709. return (attributeType != null) ? a.GetCustomAttributes(attributeType).ToArray() : a.GetCustomAttributes().ToArray();
  710. }
  711. if (provider is MemberInfo memberInfo)
  712. {
  713. return (attributeType != null) ? memberInfo.GetCustomAttributes(attributeType, inherit).ToArray() : memberInfo.GetCustomAttributes(inherit).ToArray();
  714. }
  715. if (provider is Module module)
  716. {
  717. return (attributeType != null) ? module.GetCustomAttributes(attributeType).ToArray() : module.GetCustomAttributes().ToArray();
  718. }
  719. if (provider is ParameterInfo parameterInfo)
  720. {
  721. return (attributeType != null) ? parameterInfo.GetCustomAttributes(attributeType, inherit).ToArray() : parameterInfo.GetCustomAttributes(inherit).ToArray();
  722. }
  723. throw new Exception("Cannot get attributes from '{0}'.".FormatWith(CultureInfo.InvariantCulture, provider));
  724. }
  725. #endif
  726. public static TypeNameKey SplitFullyQualifiedTypeName(string fullyQualifiedTypeName)
  727. {
  728. int? assemblyDelimiterIndex = GetAssemblyDelimiterIndex(fullyQualifiedTypeName);
  729. string typeName;
  730. string assemblyName;
  731. if (assemblyDelimiterIndex != null)
  732. {
  733. typeName = fullyQualifiedTypeName.Trim(0, assemblyDelimiterIndex.GetValueOrDefault());
  734. assemblyName = fullyQualifiedTypeName.Trim(assemblyDelimiterIndex.GetValueOrDefault() + 1, fullyQualifiedTypeName.Length - assemblyDelimiterIndex.GetValueOrDefault() - 1);
  735. }
  736. else
  737. {
  738. typeName = fullyQualifiedTypeName;
  739. assemblyName = null;
  740. }
  741. return new TypeNameKey(assemblyName, typeName);
  742. }
  743. private static int? GetAssemblyDelimiterIndex(string fullyQualifiedTypeName)
  744. {
  745. // we need to get the first comma following all surrounded in brackets because of generic types
  746. // 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
  747. int scope = 0;
  748. for (int i = 0; i < fullyQualifiedTypeName.Length; i++)
  749. {
  750. char current = fullyQualifiedTypeName[i];
  751. switch (current)
  752. {
  753. case '[':
  754. scope++;
  755. break;
  756. case ']':
  757. scope--;
  758. break;
  759. case ',':
  760. if (scope == 0)
  761. {
  762. return i;
  763. }
  764. break;
  765. }
  766. }
  767. return null;
  768. }
  769. public static MemberInfo GetMemberInfoFromType(Type targetType, MemberInfo memberInfo)
  770. {
  771. const BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
  772. switch (memberInfo.MemberType())
  773. {
  774. case MemberTypes.Property:
  775. PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
  776. Type[] types = propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray();
  777. return targetType.GetProperty(propertyInfo.Name, bindingAttr, null, propertyInfo.PropertyType, types, null);
  778. default:
  779. return targetType.GetMember(memberInfo.Name, memberInfo.MemberType(), bindingAttr).SingleOrDefault();
  780. }
  781. }
  782. public static IEnumerable<FieldInfo> GetFields(Type targetType, BindingFlags bindingAttr)
  783. {
  784. ValidationUtils.ArgumentNotNull(targetType, nameof(targetType));
  785. List<MemberInfo> fieldInfos = new List<MemberInfo>(targetType.GetFields(bindingAttr));
  786. #if !PORTABLE
  787. // Type.GetFields doesn't return inherited private fields
  788. // manually find private fields from base class
  789. GetChildPrivateFields(fieldInfos, targetType, bindingAttr);
  790. #endif
  791. return fieldInfos.Cast<FieldInfo>();
  792. }
  793. #if !PORTABLE
  794. private static void GetChildPrivateFields(IList<MemberInfo> initialFields, Type targetType, BindingFlags bindingAttr)
  795. {
  796. // fix weirdness with private FieldInfos only being returned for the current Type
  797. // find base type fields and add them to result
  798. if ((bindingAttr & BindingFlags.NonPublic) != 0)
  799. {
  800. // modify flags to not search for public fields
  801. BindingFlags nonPublicBindingAttr = bindingAttr.RemoveFlag(BindingFlags.Public);
  802. while ((targetType = targetType.BaseType()) != null)
  803. {
  804. // filter out protected fields
  805. IEnumerable<FieldInfo> childPrivateFields =
  806. targetType.GetFields(nonPublicBindingAttr).Where(f => f.IsPrivate);
  807. initialFields.AddRange(childPrivateFields);
  808. }
  809. }
  810. }
  811. #endif
  812. public static IEnumerable<PropertyInfo> GetProperties(Type targetType, BindingFlags bindingAttr)
  813. {
  814. ValidationUtils.ArgumentNotNull(targetType, nameof(targetType));
  815. List<PropertyInfo> propertyInfos = new List<PropertyInfo>(targetType.GetProperties(bindingAttr));
  816. // GetProperties on an interface doesn't return properties from its interfaces
  817. if (targetType.IsInterface())
  818. {
  819. foreach (Type i in targetType.GetInterfaces())
  820. {
  821. propertyInfos.AddRange(i.GetProperties(bindingAttr));
  822. }
  823. }
  824. GetChildPrivateProperties(propertyInfos, targetType, bindingAttr);
  825. // a base class private getter/setter will be inaccessible unless the property was gotten from the base class
  826. for (int i = 0; i < propertyInfos.Count; i++)
  827. {
  828. PropertyInfo member = propertyInfos[i];
  829. if (member.DeclaringType != targetType)
  830. {
  831. PropertyInfo declaredMember = (PropertyInfo)GetMemberInfoFromType(member.DeclaringType, member);
  832. propertyInfos[i] = declaredMember;
  833. }
  834. }
  835. return propertyInfos;
  836. }
  837. public static BindingFlags RemoveFlag(this BindingFlags bindingAttr, BindingFlags flag)
  838. {
  839. return ((bindingAttr & flag) == flag)
  840. ? bindingAttr ^ flag
  841. : bindingAttr;
  842. }
  843. private static void GetChildPrivateProperties(IList<PropertyInfo> initialProperties, Type targetType, BindingFlags bindingAttr)
  844. {
  845. // fix weirdness with private PropertyInfos only being returned for the current Type
  846. // find base type properties and add them to result
  847. // also find base properties that have been hidden by subtype properties with the same name
  848. while ((targetType = targetType.BaseType()) != null)
  849. {
  850. foreach (PropertyInfo propertyInfo in targetType.GetProperties(bindingAttr))
  851. {
  852. PropertyInfo subTypeProperty = propertyInfo;
  853. if (!subTypeProperty.IsVirtual())
  854. {
  855. if (!IsPublic(subTypeProperty))
  856. {
  857. // have to test on name rather than reference because instances are different
  858. // depending on the type that GetProperties was called on
  859. int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name);
  860. if (index == -1)
  861. {
  862. initialProperties.Add(subTypeProperty);
  863. }
  864. else
  865. {
  866. PropertyInfo childProperty = initialProperties[index];
  867. // don't replace public child with private base
  868. if (!IsPublic(childProperty))
  869. {
  870. // replace nonpublic properties for a child, but gotten from
  871. // the parent with the one from the child
  872. // the property gotten from the child will have access to private getter/setter
  873. initialProperties[index] = subTypeProperty;
  874. }
  875. }
  876. }
  877. else
  878. {
  879. int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name
  880. && p.DeclaringType == subTypeProperty.DeclaringType);
  881. if (index == -1)
  882. {
  883. initialProperties.Add(subTypeProperty);
  884. }
  885. }
  886. }
  887. else
  888. {
  889. Type subTypePropertyDeclaringType = subTypeProperty.GetBaseDefinition()?.DeclaringType ?? subTypeProperty.DeclaringType;
  890. int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name
  891. && p.IsVirtual()
  892. && (p.GetBaseDefinition()?.DeclaringType ?? p.DeclaringType).IsAssignableFrom(subTypePropertyDeclaringType));
  893. // don't add a virtual property that has an override
  894. if (index == -1)
  895. {
  896. initialProperties.Add(subTypeProperty);
  897. }
  898. }
  899. }
  900. }
  901. }
  902. public static bool IsMethodOverridden(Type currentType, Type methodDeclaringType, string method)
  903. {
  904. bool isMethodOverriden = currentType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
  905. .Any(info =>
  906. info.Name == method &&
  907. // check that the method overrides the original on DynamicObjectProxy
  908. info.DeclaringType != methodDeclaringType
  909. && info.GetBaseDefinition().DeclaringType == methodDeclaringType
  910. );
  911. return isMethodOverriden;
  912. }
  913. public static object GetDefaultValue(Type type)
  914. {
  915. if (!type.IsValueType())
  916. {
  917. return null;
  918. }
  919. switch (ConvertUtils.GetTypeCode(type))
  920. {
  921. case PrimitiveTypeCode.Boolean:
  922. return false;
  923. case PrimitiveTypeCode.Char:
  924. case PrimitiveTypeCode.SByte:
  925. case PrimitiveTypeCode.Byte:
  926. case PrimitiveTypeCode.Int16:
  927. case PrimitiveTypeCode.UInt16:
  928. case PrimitiveTypeCode.Int32:
  929. case PrimitiveTypeCode.UInt32:
  930. return 0;
  931. case PrimitiveTypeCode.Int64:
  932. case PrimitiveTypeCode.UInt64:
  933. return 0L;
  934. case PrimitiveTypeCode.Single:
  935. return 0f;
  936. case PrimitiveTypeCode.Double:
  937. return 0.0;
  938. case PrimitiveTypeCode.Decimal:
  939. return 0m;
  940. case PrimitiveTypeCode.DateTime:
  941. return new DateTime();
  942. #if HAVE_BIG_INTEGER
  943. case PrimitiveTypeCode.BigInteger:
  944. return new BigInteger();
  945. #endif
  946. case PrimitiveTypeCode.Guid:
  947. return new Guid();
  948. #if !NET20
  949. case PrimitiveTypeCode.DateTimeOffset:
  950. return new DateTimeOffset();
  951. #endif
  952. }
  953. if (IsNullable(type))
  954. {
  955. return null;
  956. }
  957. // possibly use IL initobj for perf here?
  958. return Activator.CreateInstance(type);
  959. }
  960. }
  961. internal readonly struct TypeNameKey : IEquatable<TypeNameKey>
  962. {
  963. internal readonly string AssemblyName;
  964. internal readonly string TypeName;
  965. public TypeNameKey(string assemblyName, string typeName)
  966. {
  967. AssemblyName = assemblyName;
  968. TypeName = typeName;
  969. }
  970. public override int GetHashCode()
  971. {
  972. return (AssemblyName?.GetHashCode() ?? 0) ^ (TypeName?.GetHashCode() ?? 0);
  973. }
  974. public override bool Equals(object obj)
  975. {
  976. if (!(obj is TypeNameKey))
  977. {
  978. return false;
  979. }
  980. return Equals((TypeNameKey)obj);
  981. }
  982. public bool Equals(TypeNameKey other)
  983. {
  984. return (AssemblyName == other.AssemblyName && TypeName == other.TypeName);
  985. }
  986. }
  987. }