StringComparer Create(culture, CompareOptions) overload (#16334)
authorAnirudh Agnihotry <anirudhagnihotry098@gmail.com>
Thu, 15 Feb 2018 01:47:14 +0000 (17:47 -0800)
committerTarek Mahmoud Sayed <tarekms@microsoft.com>
Thu, 15 Feb 2018 01:47:14 +0000 (17:47 -0800)
* String Create options overlaod

* Minor Change

* Feedback

* validation on options

* obsolete removed

* Implementing Iserializable and removing ignorecase

* HashCode and serialization changes

* made inline

* Space Corrected

src/mscorlib/shared/System/StringComparer.cs

index 73c0135..b5f20c9 100644 (file)
@@ -13,8 +13,8 @@ namespace System
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
     public abstract class StringComparer : IComparer, IEqualityComparer, IComparer<string>, IEqualityComparer<string>
     {
-        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 CultureAwareComparer s_invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, CompareOptions.None);
+        private static readonly CultureAwareComparer s_invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, CompareOptions.IgnoreCase);
         private static readonly OrdinalCaseSensitiveComparer s_ordinal = new OrdinalCaseSensitiveComparer();
         private static readonly OrdinalIgnoreCaseComparer s_ordinalIgnoreCase = new OrdinalIgnoreCaseComparer();        
 
@@ -38,7 +38,7 @@ namespace System
         {
             get
             {
-                return new CultureAwareComparer(CultureInfo.CurrentCulture, false);
+                return new CultureAwareComparer(CultureInfo.CurrentCulture, CompareOptions.None);
             }
         }
 
@@ -46,7 +46,7 @@ namespace System
         {
             get
             {
-                return new CultureAwareComparer(CultureInfo.CurrentCulture, true);
+                return new CultureAwareComparer(CultureInfo.CurrentCulture, CompareOptions.IgnoreCase);
             }
         }
 
@@ -94,8 +94,18 @@ namespace System
             {
                 throw new ArgumentNullException(nameof(culture));
             }
+            
+            return new CultureAwareComparer(culture, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
+        }
+
+        public static StringComparer Create(CultureInfo culture, CompareOptions options)
+        {
+            if (culture == null)
+            {
+                throw new ArgumentException(nameof(culture));
+            }
 
-            return new CultureAwareComparer(culture, ignoreCase);
+            return new CultureAwareComparer(culture, options);
         }
 
         public int Compare(object x, object y)
@@ -123,7 +133,6 @@ namespace System
             throw new ArgumentException(SR.Argument_ImplementIComparable);
         }
 
-
         public new bool Equals(Object x, Object y)
         {
             if (x == y) return true;
@@ -163,32 +172,50 @@ namespace System
 
     [Serializable]
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
-    public sealed class CultureAwareComparer : StringComparer
+    public sealed class CultureAwareComparer : StringComparer, ISerializable
     {
+        private const CompareOptions ValidCompareMaskOffFlags = ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort);
+
         private readonly CompareInfo _compareInfo; // Do not rename (binary serialization)
-        private readonly bool _ignoreCase; // Do not rename (binary serialization)
+        private CompareOptions _options;
 
-        internal CultureAwareComparer(CultureInfo culture, bool ignoreCase)
+        internal CultureAwareComparer(CultureInfo culture, CompareOptions compareOptions)
         {
             _compareInfo = culture.CompareInfo;
-            _ignoreCase = ignoreCase;
+
+            if ((compareOptions & CultureAwareComparer.ValidCompareMaskOffFlags) != 0)
+            {
+                throw new ArgumentException(SR.Argument_InvalidFlag, nameof(compareOptions));
+            }
+            _options = compareOptions;
         }
 
-        private CompareOptions Options => _ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
+        private CultureAwareComparer(SerializationInfo info, StreamingContext context)
+        {
+            _compareInfo = (CompareInfo)info.GetValue("_compareInfo", typeof(CompareInfo));
+            bool ignoreCase = info.GetBoolean("_ignoreCase");
+
+            var obj = info.GetValueNoThrow("_options", typeof(CompareOptions));
+            if (obj != null)
+                _options = (CompareOptions)obj;
+
+            // fix up the _options value in case we are getting old serialized object not having _options
+            _options |= ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
+        }
 
         public override int Compare(string x, string y)
         {
             if (object.ReferenceEquals(x, y)) return 0;
             if (x == null) return -1;
             if (y == null) return 1;
-            return _compareInfo.Compare(x, y, Options);
+            return _compareInfo.Compare(x, y, _options);
         }
 
         public override bool Equals(string x, string y)
         {
             if (object.ReferenceEquals(x, y)) return true;
             if (x == null || y == null) return false;
-            return _compareInfo.Compare(x, y, Options) == 0;
+            return _compareInfo.Compare(x, y, _options) == 0;
         }
 
         public override int GetHashCode(string obj)
@@ -197,7 +224,7 @@ namespace System
             {
                 throw new ArgumentNullException(nameof(obj));
             }
-            return _compareInfo.GetHashCodeOfString(obj, Options);
+            return _compareInfo.GetHashCodeOfString(obj, _options);
         }
 
         // Equals method for the comparer itself.
@@ -206,14 +233,20 @@ namespace System
             CultureAwareComparer comparer = obj as CultureAwareComparer;
             return
                 comparer != null &&
-                _ignoreCase == comparer._ignoreCase &&
+                _options == comparer._options &&
                 _compareInfo.Equals(comparer._compareInfo);
         }
 
         public override int GetHashCode()
         {
-            int hashCode = _compareInfo.GetHashCode();
-            return _ignoreCase ? ~hashCode : hashCode;
+            return _compareInfo.GetHashCode() ^ ((int)_options & 0x7FFFFFFF);
+        }
+
+        public void GetObjectData(SerializationInfo info, StreamingContext context)
+        {
+            info.AddValue("_compareInfo", _compareInfo);
+            info.AddValue("_options", _options);
+            info.AddValue("_ignoreCase", (_options & CompareOptions.IgnoreCase) != 0);
         }
     }