0

DataGridView があり、カスタム ソーター (System.Collections.IComparer から派生) を使用する必要があります。それはうまく機能していましたが、基になるデータ型に関係なく、セルで文字列比較を行うことになるため、比較が正しく行われていないことに気付きました。(1, 2, 10) の代わりに (つまり、1, 10, 2)。

データ型に関係なく列を適切に比較できる比較関数を作成するにはどうすればよいですか?

public int compare(object x, object y)
{
    DataGridViewRow dr1 = (DataGridViewRow)x;
    DataGridViewRow dr2 = (DataGridViewRow)y;

    object cell1 = dr1.Cells["SomeName"].Value;
    object cell2 = dr2.Cells["SomeName"].Value;

    //Compare cell1 and cell 2 based on the data type in
    //dr1.Cells["SomeName"].ValueType.
}
4

2 に答える 2

2

この問題の解決には、いくつかの重要な部分があるようです。

  1. 同様のタイプを比較していることを確認してください。
  2. タイプのインスタンスを比較できることを確認してください。

ここにあなたが始めるためのいくつかのアイデアがあります。わかりやすくするために、エラーチェックは省略しました。

推定:

Type type1 = dr1.Cells["SomeName"].ValueType;
Type type2 = dr2.Cells["SomeName"].ValueType;

次に、一方の値をもう一方のタイプに強制変換できるかどうかを確認します。

if (type1 != type2)
{
    TypeConverter tc1 = TypeDescriptor.GetConverter(type1);
    TypeConverter tc2 = TypeDescriptor.GetConverter(type2);

    if (tc1.CanConvertFrom(type2))
    {
        cell2 = tc1.ConvertFrom(cell2);
        type2 = type1;
    }
    else if (tc1.CanConvertTo(type2))
    { 
        cell1 = tc1.ConvertTo(cell1, type2);
        type1 = type2;
    }
    else if (tc2.CanConvertFrom(type1))
    {
        cell1 = tc2.ConvertFrom(cell1);
        type1 = type2;
    }
    else if (tc2.CanConvertTo(type1))
    { 
        cell2 = tc2.ConvertTo(cell2, type1);
        type2 = type1;
    }
    else // fallback to string comparison
    {
        cell1 = tc1.ConvertToString(cell1);        
        type1 = cell1.GetType();

        cell2 = tc2.ConvertToString(cell2);        
        type2 = cell2.GetType();
    }
    // cell1 and cell2 should be the same type now
}

同様のタイプのインスタンスができたので、それらを比較する方法を見つける必要があります。

C#4を使用している場合、動的キーワードは友達かもしれません。

dynamic c1 = cell1;
try 
{
    int compareResult = c1.CompareTo(cell2);
}
catch(Exception)
{
    // type1 doesn't implement an IComparable-like interface
}

C#4を使用していない場合は、値が以下を実装しているかどうかを確認できますIComparable

if (cell1 is IComparable)
{
   int compareResult = ((IComparable)cell1).CompareTo(cell2);
}

または、おそらくそれはジェネリックIComparable<T>を実装します。その場合、いくつかのリフレクショントリックに頼る必要があるかもしれません:

Type genericComparableType = typeof(IComparable<>);
Type typedComparableType = genericComparableType.MakeGenericType(new Type[] { type1 });
if (typedComparableType.IsInstanceOfType(cell1))
{
    MethodInfo compareTo = typedComparableType.GetMethod("CompareTo", new Type[] { type1 });
    int compareResult = (int)compareTo.Invoke(cell1, new object[] { cell2 });
}

最後に、Comparer<T>.Defaultリフレクションを使用して、機能するかどうかを確認できます。

Type genericComparerType = typeof(Comparer<>);
Type typedComparerType = genericComparerType.MakeGenericType(new Type[] { type1 });
PropertyInfo defaultProperty = typedComparerType.GetProperty("Default", BindingFlags.Static | BindingFlags.Public);

object defaultComparer = defaultProperty.GetValue(null, null);
MethodInfo compare = defaultComparer.GetType().GetMethod("Compare", new Type[] { type1, type1 });
int compareResult = (int)compare.Invoke(defaultComparer, new object[] { cell1, cell2 });

これらのいずれも機能しない場合は、文字列比較にフォールバックする必要があります。

于 2012-07-03T01:28:36.007 に答える
0

適切な型にキャストする

Int32 i1 = Int32.Parse(cell1.Tostring());

Int32 i2 = Int32.Parse(cell2.Tostring());

return i1.Compare(i2);
于 2012-07-03T00:27:16.333 に答える