List.Sort声称我的IComparer不一致

时间:2017-03-15 20:31:08

标签: c# sorting generics

我有一个tblDetail对象列表。 tblDetails有txtTracked,一个字符串。我想根据这个属性进行排序。所以我这样做:

switch (sortby)
{
    //...
    case "Tracked Y/N":
        list.Sort((lhs, rhs) => {
            return lhs.txtTracked.CompareTo(rhs.txtTracked);
        });
        break;
    case "Tracked Y/N-desc":
        list.Sort((lhs, rhs) => {
            return -lhs.txtTracked.CompareTo(rhs.txtTracked);
        });
        break;
    //...
}

除非有时txtTracked为null。好的,很好,所以我这样做:

switch (sortby)
{
    //...
    case "Tracked Y/N":
        list.Sort((lhs, rhs) => {
            string toCompare = lhs.txtTracked;
            if (toCompare == null)
                toCompare = "";
            return toCompare.CompareTo(rhs.txtTracked);
        });
        break;
    case "Tracked Y/N-desc":
        list.Sort((lhs, rhs) => {
            string toCompare = lhs.txtTracked;
            if (toCompare == null)
                toCompare = "";
            return -toCompare.CompareTo(rhs.txtTracked);
        });
        break;
    //...
}

常规升序排序工作正常,但出于某种原因,当我在同一组数据上使用降序排序时,我在"跟踪Y / N-desc&#34中的lhs上得到空引用异常;。所以我这样做:

switch (sortby)
{
    //...
    case "Tracked Y/N":
        list.Sort((lhs, rhs) => {
            string toCompare = lhs.txtTracked;
            if (toCompare == null)
                toCompare = "";
            return toCompare.CompareTo(rhs.txtTracked);
        });
        break;
    case "Tracked Y/N-desc":
        //for some reason this sort adds null into the list. wat.
        list.Sort((lhs, rhs) => {
            if (lhs == null)
                return 1;
            if (rhs == null)
                return -1;
            string toCompare = lhs.txtTracked;
            if (toCompare == null)
                toCompare = "";
            return -toCompare.CompareTo(rhs.txtTracked);
        });
        list.RemoveAll(d => d == null);
        break;
    //...
}

现在我收到一个新错误:

Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results.

是什么给出的?它的工作方式很好,但不是另一种方式。 C#如何确定我的排序功能不够好,我怎样才能做到正确?

另外,当我调用sort时,为什么null会被添加到我的列表中?

3 个答案:

答案 0 :(得分:1)

到目前为止,您很幸运升序并没有抛出空引用异常。或者应该这样,你还没有引起你的注意。

您的一个(或多个)对象为null。当您使用升序排序时,它恰好出现在rhs上,并且在降序排列时出现了lhs。 rhs == null是可以的,因为CompareTo方法可以解决这个问题。但是如果lhs == null,你会得到一个例外。

已经存在一种空安全方法,它允许lhs和rhs中的一个/两个为空:静态String.Compare(String, String)。您可以将此方法与null-safe navigation operator ?.一起使用,如下所示:

list.Sort((lhs, rhs) => { return String.Compare(lhs?.txtTracked, rhs?.txtTracked); });

用于升序排序,

list.Sort((lhs, rhs) => { return String.Compare(rhs?.txtTracked, lhs?.txtTracked); });

降序排序。

答案 1 :(得分:1)

您:

    list.Sort((lhs, rhs) => {
        if (lhs == null)
            return 1;
        if (rhs == null)
            return -1;
        // more cases
    });

这不起作用,因为如果两个比较都是null,它将始终返回正数。因此排序算法永远不会正确。一旦它交换了两个null,因为它们的顺序错误,例如它们仍然是错误的顺序。

如果xy相比不是零,那么您提出的问题与y相比,x的符号必须相反。

相反,你可以这样做:

    list.Sort((lhs, rhs) => {
        if (lhs == null || rhs == null)
            return Comparer<object>.Default.Compare(rhs, lhs);
        return string.Compare(rhs.txtTracked, lhs.txtTracked);
    });

如果其中一个或两个是null,我只是将它们作为对象进行比较。那可行。你也可以用另一种方式写它:

    list.Sort((lhs, rhs) => {
        if (lhs == null || rhs == null)
            return (rhs != null).CompareTo(lhs != null);
        return string.Compare(rhs.txtTracked, lhs.txtTracked);
    });

这种方式使用了false小于true的事实。

答案 2 :(得分:-1)

尝试切换desc的变量。

list.Sort((lhs, rhs) => {
            return (rhs.txtTracked ?? "").CompareTo(lhs.txtTracked ?? "");
        });