-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Expand file tree
/
Copy pathAttribute.cs
More file actions
141 lines (115 loc) · 5.21 KB
/
Attribute.cs
File metadata and controls
141 lines (115 loc) · 5.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
namespace System
{
[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
[Serializable]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public abstract partial class Attribute
{
protected Attribute() { }
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern",
Justification = "Unused fields don't make a difference for equality")]
public override bool Equals([NotNullWhen(true)] object? obj)
{
if (obj == null)
return false;
if (this.GetType() != obj.GetType())
return false;
Type thisType = this.GetType();
object thisObj = this;
object? thisResult, thatResult;
while (thisType != typeof(Attribute))
{
FieldInfo[] thisFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
for (int i = 0; i < thisFields.Length; i++)
{
thisResult = thisFields[i].GetValue(thisObj);
thatResult = thisFields[i].GetValue(obj);
if (!AreFieldValuesEqual(thisResult, thatResult))
{
return false;
}
}
thisType = thisType.BaseType!;
}
return true;
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern",
Justification = "Unused fields don't make a difference for hashcode quality")]
public override int GetHashCode()
{
Type type = GetType();
while (type != typeof(Attribute))
{
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
object? vThis = null;
for (int i = 0; i < fields.Length; i++)
{
object? fieldValue = fields[i].GetValue(this);
// The hashcode of an array ignores the contents of the array, so it can produce
// different hashcodes for arrays with the same contents.
// Since we do deep comparisons of arrays in Equals(), this means Equals and GetHashCode will
// be inconsistent for arrays. Therefore, we ignore hashes of arrays.
if (fieldValue != null && !fieldValue.GetType().IsArray)
vThis = fieldValue;
if (vThis != null)
break;
}
if (vThis != null)
return vThis.GetHashCode();
type = type.BaseType!;
}
return type.GetHashCode();
}
// Compares values of custom-attribute fields.
private static bool AreFieldValuesEqual(object? thisValue, object? thatValue)
{
if (thisValue == null && thatValue == null)
return true;
if (thisValue == null || thatValue == null)
return false;
Type thisValueType = thisValue.GetType();
if (thisValueType.IsArray)
{
// Ensure both are arrays of the same type.
if (!thisValueType.Equals(thatValue.GetType()))
{
return false;
}
Array thisValueArray = (Array)thisValue;
Array thatValueArray = (Array)thatValue;
if (thisValueArray.Length != thatValueArray.Length)
{
return false;
}
// Attributes can only contain single-dimension arrays, so we don't need to worry about
// multidimensional arrays.
Debug.Assert(thisValueArray.Rank == 1 && thatValueArray.Rank == 1);
for (int j = 0; j < thisValueArray.Length; j++)
{
if (!AreFieldValuesEqual(thisValueArray.GetValue(j), thatValueArray.GetValue(j)))
{
return false;
}
}
}
else
{
// An object of type Attribute will cause a stack overflow.
// However, this should never happen because custom attributes cannot contain values other than
// constants, single-dimensional arrays and typeof expressions.
Debug.Assert(!(thisValue is Attribute));
if (!thisValue.Equals(thatValue))
return false;
}
return true;
}
public virtual object TypeId => GetType();
public virtual bool Match(object? obj) => Equals(obj);
public virtual bool IsDefaultAttribute() => false;
}
}