使用OrderBy扩展时的默认比较器

时间:2016-05-02 13:25:01

标签: c# compare

出于好奇:使用以下扩展方法对一堆对象进行排序时使用了什么比较器?

OrderBy(x=> x)

背景:我必须检查两个ISet< T>实例包含相同的元素,并考虑使用

bool setsEqual = MySet.SequenceEqual(OtherSet);

方法。由于集合中包含的那些元素的顺序未定义且可能不同,因此在内部顺序不相同的情况下,SequenceEqual将失败。所以我必须明确定义一个订单。由于订单算法本身完全不相关,只要它稳定,我只使用“身份”lambda表达式:

bool setsEqual = MySet.OrderBy(x => x).SequenceEqual(OtherSet.OrderBy(x => x);

但是“比较对象本身”对代码意味着什么呢?由于这个OrderBy扩展方法是通用的,所以必须有一个默认的比较算法,它能够在不知道更多关于它的情况下对对象进行排序,这意味着必须将排序的比较委托给集合的类型。元素本身。是否存在元素类型必须支持的接口,或者是否存在默认比较器(可能是比较对象的内部存储器地址)?

3 个答案:

答案 0 :(得分:1)

要回答排序问题:排序使用IComparable<T>IComperable(如果未实施)。 IComperable接口强制您实施int CompareTo(object)方法(或int CompareTo(T)方法,如果您使用的是打字版本)。

元素的顺序由int的符号决定。返回的值解释如下:

  • 0:这两个对象是等价的(即相同的)
  • -1:比较对象此对象之前(即在此对象之前)
  • 1:比较对象跟随此对象(即在此对象之后)

忽略实际值,标志是最重要的。如果您实现自己的IComparable接口,则必须选择排序顺序的语义。

许多对象已经实现了IComparable,就像你的所有数字,字符串等一样。如果你需要对你自己创建的对象进行排序,你需要明确地实现它。如果您打算将这些对象显示在屏幕上的列表中,这并不是一种不好的做法。

至于您的具体情况,您只需确定一个集合和另一个IEnumerable是否相同,那么您将使用在ISet<T>.SetEquals(IEnumerable<T>)中实现的方法标准库集实现。根据定义,集合仅保证值是唯一的,因此只要元素的数量相同,您只需要检测一个IEnumerable中的所有元素都可以在集合中找到。

答案 1 :(得分:0)

该方法使用IComparable<T> - 或IComparable - 接口,具体取决于两者中的哪一个。如果没有实现,则顺序是任意的。

但是,在比较集合之前,您不需要为实例订购。只需循环一组并检查其所有元素是否都包含在另一组中。或者使用它:

var areEqual = firstSet.All(x => secondSet.Contains(x)) && secondSet.All(x => firstSet.Contains(x));

甚至更简单:

var areEqual = !firstSet.Except(secondSet).Any() && !secondSet.Except(firstSet).Any();

两种方式的执行速度比您的appraoch快得多,因为当找到第一个不适合的元素时,元素的迭代会停止。使用OrderBy将循环所有元素,无论是否已存在不匹配。

答案 2 :(得分:0)

与平等不同,没有&#39;默认&#39;比较一般的对象。 对于任何类型Comparer<TKey>.DefaultTKey似乎总是返回比较器。如果无法确定合理的比较方法,则会出现异常,但只有在使用比较器时才会出现异常。

  

至少有一个对象必须实现IComparable。