0

設定

カスタム 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 がありません。行は手動で追加されています。
  • エラーのスタック トレースの深さは 1 レベルのみです。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返されます...

4

2 に答える 2

4

juharrは正しいですが、彼が正しい理由は次のとおりです。

の実装Compareは対称的ではありません。つまりrow1.ReadOnly == falserow2.ReadOnly == falseを返すと、「は」よりも小さい-1ことを意味します。同じ値でその比較を逆にすると、は未満になります。これは、対称である必要があるソートアルゴリズムを混乱させる可能性があります。row1 row2row2 row1Compare

正しい比較は次のようになります。

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

これがbool.CompareTo(bool)返される可能性が高いため、「回避策」(私の意見ではより良い解決策)が機能します。

于 2013-01-08T17:02:29.510 に答える
2

問題は-1、両方が。を持っているときに戻ってくることReadOnlyですfalse。その場合は戻ってください0

最初のifステートメントを次のように変更するだけです

 if((row1.ReadOnly && row2.ReadOnly) || !(row1.ReadOnly || row2.ReadOnly))
于 2013-01-08T16:51:42.167 に答える