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 
5 
6 using System.Runtime.CompilerServices;
7 
8 using Internal.IntrinsicSupport;
9 
10 namespace System.Collections.Generic
11 {
12     [Serializable]
13     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
14     public abstract class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T>
15     {
16         // WARNING: We allow diagnostic tools to directly inspect this member (_default).
17         // See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details.
18         // Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools.
19         // Get in touch with the diagnostics team if you have questions.
20         private static EqualityComparer<T> _default;
21 
22         [Intrinsic]
Create()23         private static EqualityComparer<T> Create()
24         {
25 #if PROJECTN
26             // The compiler will overwrite the Create method with optimized
27             // instantiation-specific implementation.
28             _default = null;
29             throw new NotSupportedException();
30 #else
31             // The compiler will overwrite the Create method with optimized
32             // instantiation-specific implementation.
33             // This body serves as a fallback when instantiation-specific implementation is unavailable.
34             return (_default = EqualityComparerHelpers.GetUnknownEquatableComparer<T>());
35 #endif
36         }
37 
EqualityComparer()38         protected EqualityComparer()
39         {
40         }
41 
42         public static EqualityComparer<T> Default
43         {
44             [Intrinsic]
45             get
46             {
47                 // Lazy initialization produces smaller code for CoreRT than initialization in constructor
48                 return _default ?? Create();
49             }
50         }
51 
Equals(T x, T y)52         public abstract bool Equals(T x, T y);
53 
GetHashCode(T obj)54         public abstract int GetHashCode(T obj);
55 
IEqualityComparer.GetHashCode(object obj)56         int IEqualityComparer.GetHashCode(object obj)
57         {
58             if (obj == null)
59                 return 0;
60             if (obj is T)
61                 return GetHashCode((T)obj);
62             throw new ArgumentException(SR.Argument_InvalidArgumentForComparison, nameof(obj));
63         }
64 
IEqualityComparer.Equals(object x, object y)65         bool IEqualityComparer.Equals(object x, object y)
66         {
67             if (x == y)
68                 return true;
69             if (x == null || y == null)
70                 return false;
71             if ((x is T) && (y is T))
72                 return Equals((T)x, (T)y);
73             throw new ArgumentException(SR.Argument_InvalidArgumentForComparison);
74         }
75     }
76 
77 #if false
78     internal sealed class DefaultEqualityComparer<T> : EqualityComparer<T>
79     {
DefaultEqualityComparer()80         public DefaultEqualityComparer()
81         {
82         }
83 
Equals(T x, T y)84         public sealed override bool Equals(T x, T y)
85         {
86             if (x == null)
87                 return y == null;
88             if (y == null)
89                 return false;
90 
91             return x.Equals(y);
92         }
93 
GetHashCode(T obj)94         public sealed override int GetHashCode(T obj)
95         {
96             if (obj == null)
97                 return 0;
98             return obj.GetHashCode();
99         }
100 
101         // Equals method for the comparer itself.
Equals(Object obj)102         public sealed override bool Equals(Object obj)
103         {
104             if (obj == null)
105             {
106                 return false;
107             }
108 
109             // This needs to use GetType instead of typeof to avoid infinite recursion in the type loader
110             return obj.GetType().Equals(GetType());
111         }
112 
113 
114         // This needs to use GetType instead of typeof to avoid infinite recursion in the type loader
GetHashCode()115         public sealed override int GetHashCode() => GetType().GetHashCode();
116     }
117 #endif
118 }
119