Remove serializable attribute from OrdinalIgnoreCaseComparer (#12215)
authorViktor Hofer <viktor.hofer@microsoft.com>
Wed, 14 Jun 2017 01:49:02 +0000 (03:49 +0200)
committerDan Moseley <danmose@microsoft.com>
Wed, 14 Jun 2017 01:49:02 +0000 (18:49 -0700)
* Remove serializable attribute from OrdinalIgnoreCaseComparer

* Introducing OrdinalCaseSensitiveComparer to serialize correctly with netfx

* Updated PR feedback

src/mscorlib/shared/System/StringComparer.cs

index 4b6193c..755b1d9 100644 (file)
@@ -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);
+        }
     }
 }