From 4da6cefa2d2f389116924ad4b8402649bffc00b8 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Wed, 14 Jun 2017 03:49:02 +0200 Subject: [PATCH] Remove serializable attribute from OrdinalIgnoreCaseComparer (dotnet/coreclr#12215) * Remove serializable attribute from OrdinalIgnoreCaseComparer * Introducing OrdinalCaseSensitiveComparer to serialize correctly with netfx * Updated PR feedback Commit migrated from https://github.com/dotnet/coreclr/commit/fe22770b9fe8f665679bde1c08d1372fb9f78e0e --- .../src/mscorlib/shared/System/StringComparer.cs | 119 ++++++++++++++++++--- 1 file changed, 107 insertions(+), 12 deletions(-) diff --git a/src/coreclr/src/mscorlib/shared/System/StringComparer.cs b/src/coreclr/src/mscorlib/shared/System/StringComparer.cs index 4b6193c..755b1d9 100644 --- a/src/coreclr/src/mscorlib/shared/System/StringComparer.cs +++ b/src/coreclr/src/mscorlib/shared/System/StringComparer.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Diagnostics.Contracts; +using System.Runtime.Serialization; namespace System { @@ -15,7 +16,7 @@ namespace System { private static readonly CultureAwareComparer s_invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, false); private static readonly CultureAwareComparer s_invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, true); - private static readonly OrdinalComparer s_ordinal = new OrdinalComparer(); + private static readonly OrdinalCaseSensitiveComparer s_ordinal = new OrdinalCaseSensitiveComparer(); private static readonly OrdinalIgnoreCaseComparer s_ordinalIgnoreCase = new OrdinalIgnoreCaseComparer(); public static StringComparer InvariantCulture @@ -228,11 +229,49 @@ namespace System [Serializable] [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - internal sealed class OrdinalComparer : StringComparer + internal class OrdinalComparer : StringComparer { - public override int Compare(string x, string y) => string.CompareOrdinal(x, y); + private readonly bool _ignoreCase; // Do not rename (binary serialization) - public override bool Equals(string x, string y) => string.Equals(x, y); + internal OrdinalComparer(bool ignoreCase) + { + _ignoreCase = ignoreCase; + } + + public override int Compare(string x, string y) + { + if (ReferenceEquals(x, y)) + return 0; + if (x == null) + return -1; + if (y == null) + return 1; + + if (_ignoreCase) + { + return string.Compare(x, y, StringComparison.OrdinalIgnoreCase); + } + + return string.CompareOrdinal(x, y); + } + + public override bool Equals(string x, string y) + { + if (ReferenceEquals(x, y)) + return true; + if (x == null || y == null) + return false; + + if (_ignoreCase) + { + if (x.Length != y.Length) + { + return false; + } + return (string.Compare(x, y, StringComparison.OrdinalIgnoreCase) == 0); + } + return x.Equals(y); + } public override int GetHashCode(string obj) { @@ -244,18 +283,72 @@ namespace System throw new ArgumentNullException(nameof(obj)); #endif } + Contract.EndContractBlock(); + + if (_ignoreCase) + { + return TextInfo.GetHashCodeOrdinalIgnoreCase(obj); + } + return obj.GetHashCode(); } - // Equals/GetHashCode methods for the comparer itself. - public override bool Equals(object obj) => obj is OrdinalComparer; - public override int GetHashCode() => nameof(OrdinalComparer).GetHashCode(); + // Equals method for the comparer itself. + public override bool Equals(object obj) + { + OrdinalComparer comparer = obj as OrdinalComparer; + if (comparer == null) + { + return false; + } + return (this._ignoreCase == comparer._ignoreCase); + } + + public override int GetHashCode() + { + int hashCode = nameof(OrdinalComparer).GetHashCode(); + return _ignoreCase ? (~hashCode) : hashCode; + } } [Serializable] - [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] - internal sealed class OrdinalIgnoreCaseComparer : StringComparer + internal sealed class OrdinalCaseSensitiveComparer : OrdinalComparer, ISerializable + { + public OrdinalCaseSensitiveComparer() : base(false) + { + } + + public override int Compare(string x, string y) => string.CompareOrdinal(x, y); + + public override bool Equals(string x, string y) => string.Equals(x, y); + + public override int GetHashCode(string obj) + { + if (obj == null) + { +#if CORECLR + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj); +#else + throw new ArgumentNullException(nameof(obj)); +#endif + } + return TextInfo.GetHashCodeOrdinalIgnoreCase(obj); + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.SetType(typeof(OrdinalComparer)); + info.AddValue("_ignoreCase", false); + } + } + + [Serializable] + internal sealed class OrdinalIgnoreCaseComparer : OrdinalComparer, ISerializable { + public OrdinalIgnoreCaseComparer() : base(true) + { + } + public override int Compare(string x, string y) => string.Compare(x, y, StringComparison.OrdinalIgnoreCase); public override bool Equals(string x, string y) => string.Equals(x, y, StringComparison.OrdinalIgnoreCase); @@ -273,8 +366,10 @@ namespace System return TextInfo.GetHashCodeOrdinalIgnoreCase(obj); } - // Equals/GetHashCode methods for the comparer itself. - public override bool Equals(object obj) => obj is OrdinalIgnoreCaseComparer; - public override int GetHashCode() => nameof(OrdinalIgnoreCaseComparer).GetHashCode(); + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.SetType(typeof(OrdinalComparer)); + info.AddValue("_ignoreCase", true); + } } } -- 2.7.4