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.
5 using System
.Diagnostics
;
6 using System
.Reflection
;
10 [AttributeUsageAttribute(AttributeTargets
.All
, Inherited
= true, AllowMultiple
= false)]
12 [System
.Runtime
.CompilerServices
.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
13 public abstract partial class Attribute
15 protected Attribute() { }
18 public override bool Equals(object? obj
)
23 if (this.GetType() != obj
.GetType())
26 Type thisType
= this.GetType();
27 object thisObj
= this;
28 object? thisResult
, thatResult
;
30 while (thisType
!= typeof(Attribute
))
32 FieldInfo
[] thisFields
= thisType
.GetFields(BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.NonPublic
| BindingFlags
.DeclaredOnly
);
34 for (int i
= 0; i
< thisFields
.Length
; i
++)
36 thisResult
= thisFields
[i
].GetValue(thisObj
);
37 thatResult
= thisFields
[i
].GetValue(obj
);
39 if (!AreFieldValuesEqual(thisResult
, thatResult
))
44 thisType
= thisType
.BaseType
!;
50 public override int GetHashCode()
52 Type type
= GetType();
54 while (type
!= typeof(Attribute
))
56 FieldInfo
[] fields
= type
.GetFields(BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.NonPublic
| BindingFlags
.DeclaredOnly
);
59 for (int i
= 0; i
< fields
.Length
; i
++)
61 object? fieldValue
= fields
[i
].GetValue(this);
63 // The hashcode of an array ignores the contents of the array, so it can produce
64 // different hashcodes for arrays with the same contents.
65 // Since we do deep comparisons of arrays in Equals(), this means Equals and GetHashCode will
66 // be inconsistent for arrays. Therefore, we ignore hashes of arrays.
67 if (fieldValue
!= null && !fieldValue
.GetType().IsArray
)
75 return vThis
.GetHashCode();
77 type
= type
.BaseType
!;
80 return type
.GetHashCode();
84 // Compares values of custom-attribute fields.
85 private static bool AreFieldValuesEqual(object? thisValue
, object? thatValue
)
87 if (thisValue
== null && thatValue
== null)
89 if (thisValue
== null || thatValue
== null)
92 Type thisValueType
= thisValue
.GetType();
94 if (thisValueType
.IsArray
)
96 // Ensure both are arrays of the same type.
97 if (!thisValueType
.Equals(thatValue
.GetType()))
102 Array thisValueArray
= (Array
)thisValue
;
103 Array thatValueArray
= (Array
)thatValue
;
104 if (thisValueArray
.Length
!= thatValueArray
.Length
)
109 // Attributes can only contain single-dimension arrays, so we don't need to worry about
110 // multidimensional arrays.
111 Debug
.Assert(thisValueArray
.Rank
== 1 && thatValueArray
.Rank
== 1);
112 for (int j
= 0; j
< thisValueArray
.Length
; j
++)
114 if (!AreFieldValuesEqual(thisValueArray
.GetValue(j
), thatValueArray
.GetValue(j
)))
122 // An object of type Attribute will cause a stack overflow.
123 // However, this should never happen because custom attributes cannot contain values other than
124 // constants, single-dimensional arrays and typeof expressions.
125 Debug
.Assert(!(thisValue
is Attribute
));
126 if (!thisValue
.Equals(thatValue
))
133 public virtual object TypeId
=> GetType();
135 public virtual bool Match(object? obj
) => Equals(obj
);
137 public virtual bool IsDefaultAttribute() => false;