Attribute.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Diagnostics;
  5. using System.Reflection;
  6. namespace System
  7. {
  8. [AttributeUsageAttribute(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
  9. [Serializable]
  10. [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
  11. public abstract partial class Attribute
  12. {
  13. protected Attribute() { }
  14. #if !CORERT
  15. public override bool Equals(object obj)
  16. {
  17. if (obj == null)
  18. return false;
  19. if (this.GetType() != obj.GetType())
  20. return false;
  21. Type thisType = this.GetType();
  22. object thisObj = this;
  23. object thisResult, thatResult;
  24. while (thisType != typeof(Attribute))
  25. {
  26. FieldInfo[] thisFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
  27. for (int i = 0; i < thisFields.Length; i++)
  28. {
  29. thisResult = thisFields[i].GetValue(thisObj);
  30. thatResult = thisFields[i].GetValue(obj);
  31. if (!AreFieldValuesEqual(thisResult, thatResult))
  32. {
  33. return false;
  34. }
  35. }
  36. thisType = thisType.BaseType;
  37. }
  38. return true;
  39. }
  40. public override int GetHashCode()
  41. {
  42. Type type = GetType();
  43. while (type != typeof(Attribute))
  44. {
  45. FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
  46. object vThis = null;
  47. for (int i = 0; i < fields.Length; i++)
  48. {
  49. object fieldValue = fields[i].GetValue(this);
  50. // The hashcode of an array ignores the contents of the array, so it can produce
  51. // different hashcodes for arrays with the same contents.
  52. // Since we do deep comparisons of arrays in Equals(), this means Equals and GetHashCode will
  53. // be inconsistent for arrays. Therefore, we ignore hashes of arrays.
  54. if (fieldValue != null && !fieldValue.GetType().IsArray)
  55. vThis = fieldValue;
  56. if (vThis != null)
  57. break;
  58. }
  59. if (vThis != null)
  60. return vThis.GetHashCode();
  61. type = type.BaseType;
  62. }
  63. return type.GetHashCode();
  64. }
  65. #endif
  66. // Compares values of custom-attribute fields.
  67. private static bool AreFieldValuesEqual(object thisValue, object thatValue)
  68. {
  69. if (thisValue == null && thatValue == null)
  70. return true;
  71. if (thisValue == null || thatValue == null)
  72. return false;
  73. Type thisValueType = thisValue.GetType();
  74. if (thisValueType.IsArray)
  75. {
  76. // Ensure both are arrays of the same type.
  77. if (!thisValueType.Equals(thatValue.GetType()))
  78. {
  79. return false;
  80. }
  81. Array thisValueArray = thisValue as Array;
  82. Array thatValueArray = thatValue as Array;
  83. if (thisValueArray.Length != thatValueArray.Length)
  84. {
  85. return false;
  86. }
  87. // Attributes can only contain single-dimension arrays, so we don't need to worry about
  88. // multidimensional arrays.
  89. Debug.Assert(thisValueArray.Rank == 1 && thatValueArray.Rank == 1);
  90. for (int j = 0; j < thisValueArray.Length; j++)
  91. {
  92. if (!AreFieldValuesEqual(thisValueArray.GetValue(j), thatValueArray.GetValue(j)))
  93. {
  94. return false;
  95. }
  96. }
  97. }
  98. else
  99. {
  100. // An object of type Attribute will cause a stack overflow.
  101. // However, this should never happen because custom attributes cannot contain values other than
  102. // constants, single-dimensional arrays and typeof expressions.
  103. Debug.Assert(!(thisValue is Attribute));
  104. if (!thisValue.Equals(thatValue))
  105. return false;
  106. }
  107. return true;
  108. }
  109. public virtual object TypeId => GetType();
  110. public virtual bool Match(object obj) => Equals(obj);
  111. public virtual bool IsDefaultAttribute() => false;
  112. }
  113. }