Improve Dictionary TryGetValue size/perfomance (dotnet/coreclr#27195)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / Attribute.cs
blob8f33c3e9df7c1a8e0ecdf5d041e89a43b941d3bb
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;
8 namespace System
10 [AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
11 [Serializable]
12 [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
13 public abstract partial class Attribute
15 protected Attribute() { }
17 #if !CORERT
18 public override bool Equals(object? obj)
20 if (obj == null)
21 return false;
23 if (this.GetType() != obj.GetType())
24 return false;
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))
41 return false;
44 thisType = thisType.BaseType!;
47 return true;
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);
57 object? vThis = null;
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)
68 vThis = fieldValue;
70 if (vThis != null)
71 break;
74 if (vThis != null)
75 return vThis.GetHashCode();
77 type = type.BaseType!;
80 return type.GetHashCode();
82 #endif
84 // Compares values of custom-attribute fields.
85 private static bool AreFieldValuesEqual(object? thisValue, object? thatValue)
87 if (thisValue == null && thatValue == null)
88 return true;
89 if (thisValue == null || thatValue == null)
90 return false;
92 Type thisValueType = thisValue.GetType();
94 if (thisValueType.IsArray)
96 // Ensure both are arrays of the same type.
97 if (!thisValueType.Equals(thatValue.GetType()))
99 return false;
102 Array thisValueArray = (Array)thisValue;
103 Array thatValueArray = (Array)thatValue;
104 if (thisValueArray.Length != thatValueArray.Length)
106 return false;
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)))
116 return false;
120 else
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))
127 return false;
130 return true;
133 public virtual object TypeId => GetType();
135 public virtual bool Match(object? obj) => Equals(obj);
137 public virtual bool IsDefaultAttribute() => false;