一个比较器何时会使排序方法抛出参数异常?

3
Sort的文档称,如果“比较器的实现在排序过程中引发错误。例如,当比较器将一个项与自身进行比较时,可能不会返回0”,则Sort会抛出ArgumentException异常。

除了给出的示例外,还有谁能告诉我这种情况什么时候会发生?

2个回答

4
排序算法(快速排序)依赖于可预测的IComparer实现。在BCL中经过数十层间接引用后,您最终会到达此方法:
public void Sort(T[] keys, int index, int length, IComparer<T> comparer)
{
    try
    {
        ...
        ArraySortHelper<T>.QuickSort(keys, index, index + (length - 1), comparer);

    }
    catch (IndexOutOfRangeException)
    {
        ...
        throw new ArgumentException(Environment.GetResourceString("Arg_BogusIComparer", values));
    }
}

进一步深入了解快速排序的实现,你会看到像这样的代码:

    while (comparer.Compare(keys[a], y) < 0)
    {
        a++;
    }
    while (comparer.Compare(y, keys[b]) < 0)
    {
        b--;
    }

基本上,如果IComparer行为不当,则Quicksort调用会抛出IndexOutOfRangeException异常,该异常被包装在ArgumentException中。

这是另一个错误的IComparer示例

class Comparer: IComparer<int>
{
    public int Compare(int x, int y)
    {
        return -1;
    }
}

我想,简短的答案是:当你的IComparer实现与文档中定义的一样不能一致地比较值时:

比较两个对象,并返回一个值表示其中一个对象是否小于、等于或大于另一个对象。


谢谢 - 在转向SO之前,这基本上是我所做的。原始错误似乎是IndexOutOfRangeException。这与比较器的可预测性有什么关系? - Brian Rasmussen
好的 - 我能理解那可能会是个问题。谢谢! - Brian Rasmussen
我进一步研究了这个问题。如果我没记错的话,比较器大部分时间可能会出现问题。只有当索引超出数组边界时才会出现问题。显然,这并不是很有用,因为比较器应该做正确的事情。 - Brian Rasmussen

3
我今天遇到了这个问题,经过调查,我发现有时我的比较器会被调用,并且x和y是引用同一个对象,但我的比较器没有返回0。一旦我解决了这个问题,我就不再出现异常了。
希望对你有所帮助,
Eric

Eric,非常好的观点,我认为这正是我卷入其中的问题。非常感谢你的帮助! - salocinx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接