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.