简体   繁体   English

无法将默认比较器作为IComparer传递<object>

[英]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: 我正在尝试调用一个“Sort”方法,该方法需要IComparer<object>类型的参数,使用以下代码:

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

It builds but at run time I get an InvalidCastException with the message: 它构建但在运行时我得到一个带有消息的InvalidCastException:

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). Comparer.Default使用对象的固有比较语义(即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. 您可以创建一个自定义IComparer<object>类,它只包含DateTime比较器,但是无法通过强制转换直接执行此操作。

If your collection always contains DateTime objects, then you can just do: 如果您的集合始终包含DateTime对象,那么您可以这样做:

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: 如果您直接使用ICollection,您可能希望使用LINQ选项来执行:

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. 如果你正在使用实现IList<T>东西(例如List<DateTime> ),你可以在列表本身上调用Sort()。


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). 如果您可以更改集合对象的类型(即从List<object>更改为ArrayList ),则可以使用非通用IComparer接口( Comparer<DateTime>.Default实现)。

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: (您总是可以实现一个实现IComparer<object> ,如下所示:

 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) (如果您的集合中有任何非DateTime项目,这将抛出异常)

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> . 只是尝试删除强制转换并让编译器选择IComparer而不是IComparer<T>

Comparer<T> implements both IComparer<T> and IComparer so it should work. Comparer<T>实现IComparer<T>IComparer因此它应该工作。

This works just fine: 这很好用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 比较器 <T> 。默认财产 - Comparer<T>.Default Property 我们应该扩展Comparer吗? <T> 或实现IComparer <T> - Should we extend Comparer<T> or implement IComparer<T> 类比较器<T> :存在的目的 IComparer.Compare 的显式实现 - Class Comparer<T>: Aim of existence the Explicit Implementations of IComparer.Compare 如何使我的通用比较器(IComparer)处理空值? - How can I make my generic comparer (IComparer) handle nulls? 为什么从比较器派生 <T> 类而不是实现IComparer的实现类 <T> 接口? - Why derive from Comparer<T> class rather than implement class that implements IComparer<T> interface? 如何对EqualityComparer使用自定义比较器 <T> 。默认? - How to use a custom comparer for EqualityComparer<T>.Default? 为类型T的复杂对象创建自定义比较器 - Creating a custom comparer for a complex object of Type T C#Comparer.Default <short> 。比较和Comparer.Default <byte> 不返回-1,0或1 - C# Comparer.Default<short>.Compare and Comparer.Default<byte> doesn't return -1, 0 or 1 为什么是List <T> 。使用Comparer排序 <int> 。默认速度是同等自定义比较器的两倍多? - Why is List<T>.Sort using Comparer<int>.Default more than twice as fast as an equivalent custom comparer? 如何在MVC项目中更改默认的IComparer? - How can I change the default IComparer in an MVC project?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM