使用自定义IComparer对DataGridView进行排序时的ArgumentOutOfRangeException

时间:2013-01-08 16:42:50

标签: c# sorting datagridview indexoutofboundsexception

设置

我有一段代码使用自定义IComparer对DataGridView进行排序:

public class CustomComparer: IComparer
{
    public int Compare(object x, object y)
    {
        DataGridViewRow row1 = (DataGridViewRow)x;
        DataGridViewRow row2 = (DataGridViewRow)y;

        if (row1.ReadOnly && row2.ReadOnly)
        {
            return 0;
        }
        else if (row1.ReadOnly && !row2.ReadOnly)
        {
            return 1;
        }
        else
        {
            return -1;
        }
}

问题

奇怪的是,当我执行以下行(填充行之后):

grid.Sort(new CustomComparer());

我收到一个带有“索引超出范围。参数:索引”消息的ArgumentOutOfRangeException。

更多事实

进一步调查显示以下内容:

  • 我正在排序的DataGridView 上面没有BindingSource - 已手动添加行。
  • 错误的堆栈跟踪只有一层深度 - 它出现在mscorlib中的InternalDictionary上
  • 奇怪的事实#1 - 只有在任何时候,我的自定义比较器返回-1才能进行任何比较
  • 如果我将Sort方法更改为不再使用CustomComparer,则不会抛出异常。

解决方法

最后一个事实让我重写了Compare()方法以推迟.NET的CompareTo方法:

DataGridViewRow row1 = (DataGridViewRow)x;
DataGridViewRow row2 = (DataGridViewRow)y;

return row1.ReadOnly.CompareTo(row2.ReadOnly);

神秘地工作。不再抛出异常。

因此,虽然我有一个解决方法,但我想知道是否有人知道为什么这可能是一个修复,以及问题可能是首先。我查看了CompareTo的实现,返回-1 ...

2 个答案:

答案 0 :(得分:4)

juharr是对的,但这是为什么他是对的:

Compare的实施不对称,这意味着如果row1.ReadOnly == falserow2.ReadOnly == false返回-1,则表示“row1 小于< / em> row2“。如果您使用相同的值来转换该比较,则row2变为小于 row1。这可能会使需要Compare对称的排序算法感到困惑。

正确的比较应该是:

    if (row1.ReadOnly == row2.ReadOnly)  // change && to ==
    {
        return 0;
    }
    else if (row1.ReadOnly && !row2.ReadOnly)
    {
        return 1;
    }
    else
    {
        return -1;
    }

这可能是bool.CompareTo(bool)将返回的原因,这就是为什么你的“解决方法”(在我看来这是一个更好的解决方案)有效。

答案 1 :(得分:2)

问题是,当-1 ReadOnly false时,您将返回0。在这种情况下,您应该返回 if((row1.ReadOnly && row2.ReadOnly) || !(row1.ReadOnly || row2.ReadOnly))

只需将您的第一个if语句更改为

即可
{{1}}