简体   繁体   中英

can't pass default comparer as IComparer<object>

I'm trying to call a "Sort" method that expects a parameter of type IComparer<object> , using the code:

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

It builds but at run time 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?

If all you want is the default comparison, this will work:

collection.Sort(Comparer<object>.Default)

Comparer.Default uses your objects' inherent comparison semantics (ie, IComparable.CompareTo).

Unfortunately, you need to have a comparer of the appropriate type.

You could make a custom IComparer<object> class that just wrapped the DateTime comparer, but there is no way to do this directly via a cast.

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

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

Edit after reading the comment:

If you're working with an ICollection directly, you may want to use the LINQ option to do:

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

If you're working with something that implements IList<T> , (such as List<DateTime> ) you can just call Sort() on the list itself.


Since you're using a non-standard class, you'll need to make your own comparer:

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

You can then call:

collection.Sort(new Comparer() );

If you can change the type of the collection object (ie to an ArrayList from a List<object> ), then you can just use the non-generic IComparer interface (which Comparer<DateTime>.Default implements).

If you can't change the type of the collection object, then you are out of luck. (You could always implement an object that implements IComparer<object> , like so:

 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 though)

EDIT:

You could also implement something a little bit more type safe, ie:

  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
            }
        }     
    }

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());

Just try to remove the cast and let the compiler to chose IComparer instead of IComparer<T> .

Comparer<T> implements both IComparer<T> and IComparer so it should work.

This works just fine:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM