Cannot pass a default comparison parameter like IComparer <object>

I am trying to call a Sort method that expects a type parameter IComparer<object>

using the code:

collection.Sort((IComparer<object>)Comparer<DateTime>.Default)

      

It builds, but at runtime I get an InvalidCastException with the message:

Unable to cast object of type
'System.Collections.Generic.GenericComparer`1[System.DateTime]'
to type 'System.Collections.Generic.IComparer`1[System.Object]'.

      

Now what?

+2


source to share


5 answers


If you want to compare by default, this will work:

collection.Sort(Comparer<object>.Default)

      



Comparer.Default uses built-in object comparison semantics (i.e. IComparable.CompareTo).

+7


source


Unfortunately, you must have a matcher of the appropriate type.

You can create your own IComparer<object>

class that just completes the DateTime mapping, but there is no way to do this directly using broadcast.

If your collection always contains DateTime objects, you can simply do:

ICollection<DateTime> collection = ...;
collection.Sort(Comparer<DateTime>.Default); // or just collection.Sort()

      


Edit after reading the comment:

If you are working with ICollection directly, you can use the LINQ option:



collection.Cast<DateTime>().OrderBy( date => date );

      

If you are working with something that implements IList<T>

(for example List<DateTime>

), you can simply call Sort () on the list itself.


Since you are using a non-standard class, you need to make your own comparator:

class Comparer : IComparer<object> {
    int Compare(object a, object b) {
         return DateTime.Compare((DateTime)a, (DateTime)b);
    }
}

      

Then you can call:

collection.Sort(new Comparer() );

      

+4


source


If you can change the type of the collection object (i.e. to ArrayList

from List<object>

), you can simply use a non-generic interface IComparer

(which is implemented Comparer<DateTime>.Default

).

If you can't change the type of the collection object, you're out of luck. (You can always implement an object that implements IComparer<object>

, for example:

 public class DateTimeComparer : IComparer<object>
    {       
        public int Compare(object x, object y)
        {
            IComparer myComparer = Comparer<DateTime>.Default as IComparer;
            return myComparer.Compare(x, y);
        }     
    }

      

(This will throw an exception if you have any non-DateTime items in your collection)

EDIT:

You can also implement something a little more secure, i.e .:

  public class DateTimeComparer : IComparer<object>
    {       
        public int Compare(object x, object y)
        {
            if ( x is DateTime && y is DateTime )
            {
                return Comparer<DateTime>.Default.Compare((DateTime) x, (DateTime) y);
            }
            else
            {
                // handle the type mismatch
            }
        }     
    }

      

+3


source


You can define an extension function like this:

public static class ComparerConversion
    {
        private class ComparerWrapper<T> : IComparer<object>
        {
            private readonly IComparer<T> comparer;

            public ComparerWrapper(IComparer<T> comparer)
            {
                this.comparer = comparer;
            }

            public int Compare(object x, object y)
            {
                return this.comparer.Compare((T)x, (T)y);
            }
        }

        public static IComparer<object> ToObjectComparer<T>(this IComparer<T> comparer)
        {
            return new ComparerWrapper<T>(comparer);
        }
    }

      

and use it like this:

List<object> collection = new List<object> { DateTime.Now.AddDays(1), DateTime.Now };
collection.Sort(Comparer<DateTime>.Default.ToObjectComparer());

      

+3


source


Just try removing the cast and letting the compiler choose IComparer

instead IComparer<T>

.

Comparer<T>

implements both IComparer<T>

and IComparer

so it should work.

This works great:

ArrayList collection = new ArrayList {DateTime.Now.AddDays(1), DateTime.Now};
collection.Sort(Comparer<DateTime>.Default);

      

+1


source







All Articles