2012-07-02 117 views
0

我有一個DataGridView,我需要使用自定義分類器(從System.Collections.IComparer派生)。這工作正常,但我注意到我沒有完全得到我的比較,因爲它最終會對單元格進行字符串比較,而不管它們的基礎數據類型如何。 (所以,1,10,2)而不是(1,2,10)。DataGridView自定義排序 - 無論數據類型如何比較?

我該如何編寫一個比較函數,它可以適當地比較列,而不管它們的數據類型如何?

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. 
} 

回答

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 }); 

如果沒有這些工作,那麼你將不得不退卻到字符串比較。

0

強制轉換爲適當類型

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

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

return i1.Compare(i2); 
+0

這隻有在單元格中的值可以轉換爲整數時纔有效。如果我理解正確,值可以是任意類型。 –

+0

第一行轉換爲適當的類型。 Int32是一個示例。所以在「SomeName」這一列中,你不知道列中的整數類型是什麼?如果是這種情況,你怎麼知道這兩行將是相同的整型?我絕對不知道這種類型,然後投入絃樂。 – Paparazzi

+0

@MonroeThomas你有一個很好的答案已經給你+1 – Paparazzi