2011-07-12 142 views
11

我想在這裏實現的是盒裝原始類型的直接值比較。盒裝值類型比較

((object)12).Equals((object)12); // Type match will result in a value comparison, 
((object)12).Equals((object)12d); // but a type mismatch will not. (false) 
object.Equals((object)12,(object)12d); // Same here. (false) 

我明白'爲什麼'。我只是看不到'如何'。

這些類型直到運行時才知道,它們可以是數據源中的任何基本類型。包括字符串,日期時間,布爾等等。 我寫下了一個擴展方法,寫出了這兩種類型的醜惡路線,然後在進行'=​​='比較之前進行投射:(爲了完整性,我包含了每一個原語類型,再加上那些我感興趣的是)

public static bool ValueEquals(this object thisObj, object compare) 
    { 
     if (thisObj is int) 
     { 
      int obj = (int)thisObj; 
      if (compare is int) 
       return (obj == (int)compare); 
      if (compare is uint) 
       return (obj == (uint)compare); 
      if (compare is decimal) 
       return (obj == (decimal)compare); 
      if (compare is float) 
       return (obj == (float)compare); 
      <... and so on for each primitive type ...> 
     } 
     if (thisObj is uint) 
     { 
      uint obj = (uint)thisObj; 
      if (compare is int) 
       return (obj == (int)compare); 
      if (compare is uint) 
       return (obj == (uint)compare); 
      <... Again for each primitive type ...> 
     } 
     if (thisObj is decimal) 
     { 
      decimal obj = (decimal)thisObj; 
      if (compare is int) 
       return (obj == (int)compare); 
      <... Etc, etc ...> 

產生的方法竟然是300條多線長,這是很好的(但醜陋的),但現在我需要做的不僅僅是「==」更多。我需要>,<,< =,> =,!=。

有什麼反射,我可以使用盒裝值類型比較?

什麼都可以嗎?

+0

所以你只是想能夠比較兩個可能包含相同值的UNLIKE盒裝值?你不需要Equals(),因爲大多數不同類型的比較返回false。我會嘗試類似... –

+0

請改用C#4.0 * dynamic *關鍵字。 –

+0

我會避免動態,因爲你更容易出現運行時問題。通過下面的解決方案,您至少會知道這兩種類型在編譯時都是可以轉換的,並且避免了很多運行時錯誤。 –

回答

8

看起來像你正在假設從arg1類型是你想要轉換的類型,所以我會使用這樣的genric。只要Arg2爲IConvertible(INT,雙,所有數字,字符串等都是IConvertible)這將工作:

public static bool ValueEquality<T1, T2>(T1 val1, T2 val2) 
    where T1 : IConvertible 
    where T2 : IConvertible 
{ 
    // convert val2 to type of val1. 
    T1 boxed2 = (T1) Convert.ChangeType(val2, typeof (T1)); 

    // compare now that same type. 
    return val1.Equals(boxed2); 
} 

**更新**製造這兩種類型的通用指定參數時,都可以推斷出並增添了更多在編譯時確保arg2的編譯時間安全,以確保它是IConvertible。

鑑於這種通用的功能,所有的現在下面返回true(不需要,因爲從第一個參數推斷指定類型參數:基於您的評論

 Console.WriteLine(ValueEquality(1, "1")); 
     Console.WriteLine(ValueEquality(2, 2.0)); 
     Console.WriteLine(ValueEquality(3, 3L)); 

UPDATE

,這裏有一個超負荷,如果你所有的都是對象,兩者都可以共存,它將根據參數調用更合適的一個:

public static bool ValueEquality(object val1, object val2) 
    { 
     if (!(val1 is IConvertible)) throw new ArgumentException("val1 must be IConvertible type"); 
     if (!(val2 is IConvertible)) throw new ArgumentException("val2 must be IConvertible type"); 

     // convert val2 to type of val1. 
     var converted2 = Convert.ChangeType(val2, val1.GetType()); 

     // compare now that same type. 
     return val1.Equals(converted2); 
    } 

而這會爲對象的工作:

 object obj1 = 1; 
     object obj2 = 1.0; 

     Console.WriteLine(ValueEquality(obj1, obj2)); 

正如我所說的,這兩個可以共存的過載,因此,如果你比較兼容IConvertible類型直接它將使用通用的,如果你只是有盒裝類型作爲對象,它將使用對象重載。

+0

不幸的是,我只有對象用作參數(盒裝值類型)。這對我不起作用。 – johnDisplayClass

+0

更新爲新的過載。你可以使用兩者,編譯器會根據顯式的IConvertible參數或對象選擇正確的。 –

+0

警告:讓'val1'是一個int,'val2'是一個大於'int.MaxValue'的長。此方法將拋出一個OverflowException而不是返回false,這在語義上是我期望發生的。 – cdhowie

3

看看使用IComparable而不是手動if - http://msdn.microsoft.com/en-us/library/system.icomparable.compareto.aspx

如果您將來需要類似的東西,請首先考慮一個操作數類型的swith,然後針對每種類型實現「操作處理程序」類,並使用方法來處理操作,如IntOpHandler.PerformOp(int left, object right)

您還可以通過首先合併多個類型(即byte,short,ushort,int,uint,long-cast to long first,然後長時間執行操作)來減少需要處理的類型數量。

+0

+1用於鑄造類似的類型。 – johnDisplayClass

+0

這必須是一個答案。問題是關於使用<, >,<=等。 而IComparable接口正在給出答案。 – IgorStack