/
ValueType.cs
90 lines (78 loc) · 3.17 KB
/
ValueType.cs
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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
/*============================================================
**
**
**
** Purpose: Base class for all value classes.
**
**
===========================================================*/
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace System
{
[Serializable]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public abstract class ValueType
{
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern",
Justification = "Trimmed fields don't make a difference for equality")]
public override unsafe bool Equals([NotNullWhen(true)] object? obj)
{
if (null == obj)
{
return false;
}
if (GetType() != obj.GetType())
{
return false;
}
// if there are no GC references in this object we can avoid reflection
// and do a fast memcmp
if (CanCompareBits(this))
{
return SpanHelpers.SequenceEqual(
ref RuntimeHelpers.GetRawData(this),
ref RuntimeHelpers.GetRawData(obj),
RuntimeHelpers.GetMethodTable(this)->GetNumInstanceFieldBytes());
}
FieldInfo[] thisFields = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
for (int i = 0; i < thisFields.Length; i++)
{
object? thisResult = thisFields[i].GetValue(this);
object? thatResult = thisFields[i].GetValue(obj);
if (thisResult == null)
{
if (thatResult != null)
return false;
}
else
if (!thisResult.Equals(thatResult))
{
return false;
}
}
return true;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool CanCompareBits(object obj);
/*=================================GetHashCode==================================
**Action: Our algorithm for returning the hashcode is a little bit complex. We look
** for the first non-static field and get its hashcode. If the type has no
** non-static fields, we return the hashcode of the type. We can't take the
** hashcode of a static member because if that member is of the same type as
** the original type, we'll end up in an infinite loop.
**Returns: The hashcode for the type.
**Arguments: None.
**Exceptions: None.
==============================================================================*/
[MethodImpl(MethodImplOptions.InternalCall)]
public extern override int GetHashCode();
public override string? ToString()
{
return this.GetType().ToString();
}
}
}