Contribute to IDE0044 (make field readonly)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / StringComparer.cs
blobf55a098306c71b1518e169fd35947933ee4af5a7
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.Collections;
6 using System.Collections.Generic;
7 using System.Globalization;
8 using System.Runtime.Serialization;
10 namespace System
12 [Serializable]
13 [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
14 public abstract class StringComparer : IComparer, IEqualityComparer, IComparer<string?>, IEqualityComparer<string?>
16 private static readonly CultureAwareComparer s_invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, CompareOptions.None);
17 private static readonly CultureAwareComparer s_invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, CompareOptions.IgnoreCase);
18 private static readonly OrdinalCaseSensitiveComparer s_ordinal = new OrdinalCaseSensitiveComparer();
19 private static readonly OrdinalIgnoreCaseComparer s_ordinalIgnoreCase = new OrdinalIgnoreCaseComparer();
21 public static StringComparer InvariantCulture
23 get
25 return s_invariantCulture;
29 public static StringComparer InvariantCultureIgnoreCase
31 get
33 return s_invariantCultureIgnoreCase;
37 public static StringComparer CurrentCulture
39 get
41 return new CultureAwareComparer(CultureInfo.CurrentCulture, CompareOptions.None);
45 public static StringComparer CurrentCultureIgnoreCase
47 get
49 return new CultureAwareComparer(CultureInfo.CurrentCulture, CompareOptions.IgnoreCase);
53 public static StringComparer Ordinal
55 get
57 return s_ordinal;
61 public static StringComparer OrdinalIgnoreCase
63 get
65 return s_ordinalIgnoreCase;
69 // Convert a StringComparison to a StringComparer
70 public static StringComparer FromComparison(StringComparison comparisonType)
72 switch (comparisonType)
74 case StringComparison.CurrentCulture:
75 return CurrentCulture;
76 case StringComparison.CurrentCultureIgnoreCase:
77 return CurrentCultureIgnoreCase;
78 case StringComparison.InvariantCulture:
79 return InvariantCulture;
80 case StringComparison.InvariantCultureIgnoreCase:
81 return InvariantCultureIgnoreCase;
82 case StringComparison.Ordinal:
83 return Ordinal;
84 case StringComparison.OrdinalIgnoreCase:
85 return OrdinalIgnoreCase;
86 default:
87 throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
91 public static StringComparer Create(CultureInfo culture, bool ignoreCase)
93 if (culture == null)
95 throw new ArgumentNullException(nameof(culture));
98 return new CultureAwareComparer(culture, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
101 public static StringComparer Create(CultureInfo culture, CompareOptions options)
103 if (culture == null)
105 throw new ArgumentException(nameof(culture));
108 return new CultureAwareComparer(culture, options);
111 public int Compare(object? x, object? y)
113 if (x == y) return 0;
114 if (x == null) return -1;
115 if (y == null) return 1;
117 if (x is string sa)
119 if (y is string sb)
121 return Compare(sa, sb);
125 if (x is IComparable ia)
127 return ia.CompareTo(y);
130 throw new ArgumentException(SR.Argument_ImplementIComparable);
133 public new bool Equals(object? x, object? y)
135 if (x == y) return true;
136 if (x == null || y == null) return false;
138 if (x is string sa)
140 if (y is string sb)
142 return Equals(sa, sb);
145 return x.Equals(y);
148 public int GetHashCode(object obj)
150 if (obj == null)
152 throw new ArgumentNullException(nameof(obj));
155 if (obj is string s)
157 return GetHashCode(s);
159 return obj.GetHashCode();
162 public abstract int Compare(string? x, string? y);
163 public abstract bool Equals(string? x, string? y);
164 #pragma warning disable CS8614 // Remove warning disable when nullable attributes are respected
165 public abstract int GetHashCode(string obj);
166 #pragma warning restore CS8614
169 [Serializable]
170 [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
171 public sealed class CultureAwareComparer : StringComparer, ISerializable
173 private const CompareOptions ValidCompareMaskOffFlags = ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort);
175 private readonly CompareInfo _compareInfo; // Do not rename (binary serialization)
176 private readonly CompareOptions _options;
178 internal CultureAwareComparer(CultureInfo culture, CompareOptions options) : this(culture.CompareInfo, options) { }
180 internal CultureAwareComparer(CompareInfo compareInfo, CompareOptions options)
182 _compareInfo = compareInfo;
184 if ((options & ValidCompareMaskOffFlags) != 0)
186 throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
188 _options = options;
191 private CultureAwareComparer(SerializationInfo info, StreamingContext context)
193 _compareInfo = (CompareInfo)info.GetValue("_compareInfo", typeof(CompareInfo))!;
194 bool ignoreCase = info.GetBoolean("_ignoreCase");
196 var obj = info.GetValueNoThrow("_options", typeof(CompareOptions));
197 if (obj != null)
198 _options = (CompareOptions)obj;
200 // fix up the _options value in case we are getting old serialized object not having _options
201 _options |= ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
204 public override int Compare(string? x, string? y)
206 if (object.ReferenceEquals(x, y)) return 0;
207 if (x == null) return -1;
208 if (y == null) return 1;
209 return _compareInfo.Compare(x, y, _options);
212 public override bool Equals(string? x, string? y)
214 if (object.ReferenceEquals(x, y)) return true;
215 if (x == null || y == null) return false;
216 return _compareInfo.Compare(x, y, _options) == 0;
219 public override int GetHashCode(string obj)
221 if (obj == null)
223 throw new ArgumentNullException(nameof(obj));
225 return _compareInfo.GetHashCodeOfString(obj, _options);
228 // Equals method for the comparer itself.
229 public override bool Equals(object? obj)
231 return
232 obj is CultureAwareComparer comparer &&
233 _options == comparer._options &&
234 _compareInfo.Equals(comparer._compareInfo);
237 public override int GetHashCode()
239 return _compareInfo.GetHashCode() ^ ((int)_options & 0x7FFFFFFF);
242 public void GetObjectData(SerializationInfo info, StreamingContext context)
244 info.AddValue("_compareInfo", _compareInfo);
245 info.AddValue("_options", _options);
246 info.AddValue("_ignoreCase", (_options & CompareOptions.IgnoreCase) != 0);
250 [Serializable]
251 [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
252 public class OrdinalComparer : StringComparer
254 private readonly bool _ignoreCase; // Do not rename (binary serialization)
256 internal OrdinalComparer(bool ignoreCase)
258 _ignoreCase = ignoreCase;
261 public override int Compare(string? x, string? y)
263 if (ReferenceEquals(x, y))
264 return 0;
265 if (x == null)
266 return -1;
267 if (y == null)
268 return 1;
270 if (_ignoreCase)
272 return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
275 return string.CompareOrdinal(x, y);
278 public override bool Equals(string? x, string? y)
280 if (ReferenceEquals(x, y))
281 return true;
282 if (x == null || y == null)
283 return false;
285 if (_ignoreCase)
287 if (x.Length != y.Length)
289 return false;
291 return CompareInfo.EqualsOrdinalIgnoreCase(ref x.GetRawStringData(), ref y.GetRawStringData(), x.Length);
293 return x.Equals(y);
296 public override int GetHashCode(string obj)
298 if (obj == null)
300 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj);
303 if (_ignoreCase)
305 return obj.GetHashCodeOrdinalIgnoreCase();
308 return obj.GetHashCode();
311 // Equals method for the comparer itself.
312 public override bool Equals(object? obj)
314 if (!(obj is OrdinalComparer comparer))
316 return false;
318 return (this._ignoreCase == comparer._ignoreCase);
321 public override int GetHashCode()
323 int hashCode = nameof(OrdinalComparer).GetHashCode();
324 return _ignoreCase ? (~hashCode) : hashCode;
328 [Serializable]
329 internal sealed class OrdinalCaseSensitiveComparer : OrdinalComparer, ISerializable
331 public OrdinalCaseSensitiveComparer() : base(false)
335 public override int Compare(string? x, string? y) => string.CompareOrdinal(x, y);
337 public override bool Equals(string? x, string? y) => string.Equals(x, y);
339 public override int GetHashCode(string obj)
341 if (obj == null)
343 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj);
345 return obj.GetHashCode();
348 public void GetObjectData(SerializationInfo info, StreamingContext context)
350 info.SetType(typeof(OrdinalComparer));
351 info.AddValue("_ignoreCase", false);
355 [Serializable]
356 internal sealed class OrdinalIgnoreCaseComparer : OrdinalComparer, ISerializable
358 public OrdinalIgnoreCaseComparer() : base(true)
362 public override int Compare(string? x, string? y) => string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
364 public override bool Equals(string? x, string? y)
366 if (ReferenceEquals(x, y))
368 return true;
371 if (x is null || y is null)
373 return false;
376 if (x.Length != y.Length)
378 return false;
381 return CompareInfo.EqualsOrdinalIgnoreCase(ref x.GetRawStringData(), ref y.GetRawStringData(), x.Length);
384 public override int GetHashCode(string obj)
386 if (obj == null)
388 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj);
390 return obj.GetHashCodeOrdinalIgnoreCase();
393 public void GetObjectData(SerializationInfo info, StreamingContext context)
395 info.SetType(typeof(OrdinalComparer));
396 info.AddValue("_ignoreCase", true);