list.Sort ArgumentException错误:IComparer不返回0(null)

时间:2011-03-28 12:41:31

标签: c# c#-3.0

我有以下问题,我无法弄清楚它来自哪里。我非常感谢你的帮助。

代码:

List<Point> lst = new List<Point>();
lst.Add(new Point(0, -2));
lst.Add(new Point(-1, -2));

lst.Sort(delegate (Point x,Point y)
{
    if (x.X == 0)
        return -1;
    else if (y.X == 0)
        return 1;
    else
    {
        double retVal1 = x.Y * 1.0 / -x.X;
        double retVal2 = y.Y * 1.0 / -y.X;
        int retVal = -Math.Sign(retVal1 - retVal2);
        return retVal;
    }
});

如果执行,我收到一个ArgumentException,说IComparer没有返回0(null)。但是,它实际上不能返回除-1,0和1之外的任何其他内容,或者?

非常感谢你的帮助!

啊,顺便说一句,我正在使用.NET 3.5

3 个答案:

答案 0 :(得分:8)

实际上错误消息说: IComparer(或它所依赖的IComparable方法)在Array.Sort调用x时没有返回零。的CompareTo(X)。 x:''x'的类型:'Point'IComparer:'System.Array + FunctorComparer`1 [System.Drawing.Point]'

如果对象相同,则必须返回0:

    lst.Sort(delegate(Point x, Point y) {
        if (x.X == y.X && x.Y == y.Y) { // you are missing this
            return 0;
        }
        if (x.X == 0)
            return -1;
        else if (y.X == 0)
            return 1;
        else {
            double retVal1 = x.Y * 1.0 / -x.X;
            double retVal2 = y.Y * 1.0 / -y.X;
            int retVal = -Math.Sign(retVal1 - retVal2);
            return retVal;
        }
    });

答案 1 :(得分:2)

您还没有完全阅读Exception-Message。它很可能表示对于同一个对象实例它不会返回0。

您的代码错误,如果传入Point的相同实例或相同的值,则需要返回0。否则他永远不会知道他什么时候完成排序并最终会陷入无休止的循环......而且我们都知道这是绝对的负面表现。

答案 2 :(得分:0)

如上所述,比较器必须为相同的值返回0,因为身份需要相等(某些东西总是等于它自己)并且相等需要等价(你可能等同地命令两个不同的东西,但是你必须等同地订购两件相同的东西。)

还有一个问题,即.X为0的检查可能会导致相同的项返回不一致的顺序,如果它们都有.X等于0.这是一个重要的规则,比较方法必须始终保持一致的是:

如果x&lt;那么y&gt; X

如果x&lt; y和y&lt; z然后x&lt; ž。

您的算法违反了第一条规则:

说a点是{0,3},b点是{0,2}

用(a,b)调用然后返回-1表示&lt; b,但用(b,a)调用返回-1表示b&lt;一个。

用以下内容替换整个内容:

lst.Sort(delegate (Point x,Point y)
{
  return (x.Y * 1.0 / -x.X).CompareTo(y.Y * 1.0 / -y.X);
});

(注意,对于相等的点,这隐含地返回0 - 我们可以添加一个显式检查,如果这是一个更重的计算作为优化,但它没有必要。

另外,这里Point System.Drawing.Point?如果是这样,那么这段代码现在很好,但如果它是其他的话,那么值得注意的是,如果Point是一个结构,代码就可以了,但如果Point是一个类,则应该包含空检查。 / p>