Mono friendly generic comparers
authorMarek Safar <marek.safar@gmail.com>
Thu, 9 Apr 2015 12:22:00 +0000 (14:22 +0200)
committerMarek Safar <marek.safar@gmail.com>
Mon, 2 May 2016 22:08:10 +0000 (00:08 +0200)
mcs/class/referencesource/mscorlib/system/collections/generic/comparer.cs
mcs/class/referencesource/mscorlib/system/collections/generic/equalitycomparer.cs

index ec1fcd68115d1febe065682f3f2c12a5cdc81388..a9801ba78c1f2c361a650ce658e37e6ae8cb4ce0 100644 (file)
@@ -63,14 +63,22 @@ namespace System.Collections.Generic
             else
 #endif
                 if (typeof(IComparable<T>).IsAssignableFrom(t)) {
+#if MONO
+                    return (Comparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(GenericComparer<>), t);
+#else
                     return (Comparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericComparer<int>), t);
+#endif
                 }
 
             // If T is a Nullable<U> where U implements IComparable<U> return a NullableComparer<U>
             if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) {
                 RuntimeType u = (RuntimeType)t.GetGenericArguments()[0];
                 if (typeof(IComparable<>).MakeGenericType(u).IsAssignableFrom(u)) {
+#if MONO
+                    return (Comparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(NullableComparer<>), t);
+#else
                     return (Comparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableComparer<int>), u);
+#endif
                 }
             }
             // Otherwise return an ObjectComparer<T>
index 09f0760c72e705c80fbe7e71c5f0d87160e61424..89bb8d10bcf50b0195e7257e84441b413a4891af 100644 (file)
@@ -53,22 +53,41 @@ namespace System.Collections.Generic
             if (t == typeof(byte)) {
                 return (EqualityComparer<T>)(object)(new ByteEqualityComparer());
             }
+
+#if MOBILE
+            // Breaks .net serialization compatibility
+            if (t == typeof (string))
+                return (EqualityComparer<T>)(object)new InternalStringComparer ();
+#endif
+
             // If T implements IEquatable<T> return a GenericEqualityComparer<T>
             if (typeof(IEquatable<T>).IsAssignableFrom(t)) {
+#if MONO
+                return (EqualityComparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(GenericEqualityComparer<>), t);
+#else
                 return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericEqualityComparer<int>), t);
+#endif
             }
             // If T is a Nullable<U> where U implements IEquatable<U> return a NullableEqualityComparer<U>
             if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) {
                 RuntimeType u = (RuntimeType)t.GetGenericArguments()[0];
                 if (typeof(IEquatable<>).MakeGenericType(u).IsAssignableFrom(u)) {
+#if MONO
+                    return (EqualityComparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(NullableEqualityComparer<>), t);
+#else
                     return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableEqualityComparer<int>), u);
+#endif
                 }
             }
             // If T is an int-based Enum, return an EnumEqualityComparer<T>
             // See the METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST and METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG cases in getILIntrinsicImplementation
             if (t.IsEnum && Enum.GetUnderlyingType(t) == typeof(int))
             {
+#if MONO
+                return (EqualityComparer<T>)RuntimeType.CreateInstanceForAnotherGenericParameter (typeof(EnumEqualityComparer<>), t);
+#else
                 return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<int>), t);
+#endif
             }
             // Otherwise return an ObjectEqualityComparer<T>
             return new ObjectEqualityComparer<T>();
@@ -404,6 +423,41 @@ namespace System.Collections.Generic
         }
     }
 
+#if MOBILE
+    [Serializable]
+    sealed class InternalStringComparer : EqualityComparer<string> {
+    
+        public override int GetHashCode (string obj)
+        {
+            if (obj == null)
+                return 0;
+            return obj.GetHashCode ();
+        }
+    
+        public override bool Equals (string x, string y)
+        {
+            if (x == null)
+                return y == null;
+
+            if ((object) x == (object) y)
+                return true;
+
+            return x.Equals (y);
+        }
+
+        internal override int IndexOf (string[] array, string value, int startIndex, int count)
+        {
+            int endIndex = startIndex + count;
+            for (int i = startIndex; i < endIndex; ++i) {
+                if (Array.UnsafeLoad (array, i) == value)
+                    return i;
+            }
+
+            return -1;
+        }
+    }
+#endif
+
 #if FEATURE_RANDOMIZED_STRING_HASHING
     // This type is not serializeable by design.  It does not exist in previous versions and will be removed 
     // Once we move the framework to using secure hashing by default.