2013-05-14 121 views
1

我在今天遇到了一些非常奇怪的行爲,同時重構了一些代碼。如何檢查泛型對象是否適用於字符串

我有一些代碼,看起來是這樣的:

private AType Blah 
    { 
     get 
     { 
      return (from something in AList 
        where _x == null || something.x == _x 
        where _y == null || something.y == _y 
        where _z == null || something.z.IsSameAs(_z) 
        select something).Single(); 
     } 
    } 

我anonomised類型和變量名,因爲它們不是這個問題很重要。

_x和something.x的類型是字符串,_y和something.y是引用類型。同樣,_z和something.z是一個具有值比較的參考類型。

我想我可以做這樣的事情:

public AType Blah 
    { 
     get { return AList.Single(something => DetailsMatch(something.x, something.y, something.z)); } 
    } 

    private bool DetailsMatch(string x, AnotherType y, AFurtherType z) 
    { 
     return NullOrCheck(_x, x) && 
       NullOrCheck(_y, y) && 
       NullOrCheck(_z, z.IsSameAs); 
    } 

    private bool NullOrCheck<T>(T value, T expected) where T : class 
    { 
     return NullOrCheck(value, v => v == expected); 
    } 

    private static bool NullOrCheck<T>(T value, Func<T,bool> check) where T : class 
    { 
     return value == null || check(value); 
    } 

這一切似乎都有道理,但讓我吃驚的一些測試啓動失敗。事實證明,相同的字符串(例如「1A04」和「1A04」)不再被認爲是相等的使用==運算符。

看了下面的Can't operator == be applied to generic types in C#?,似乎可能是字符串在引用相等而不是以正常方式進行比較。

有沒有一種安全的方式來做到這一點在c#中或應該使用==在泛型方法被認爲是危險的上述原因?

只是爲了確認,這是我的修復包括內聯的字符串的情況下違規方法產生的問題:

private bool DetailsMatch(string x, AnotherType y, AFurtherType z) 
    { 
     return (_x == null || _x == x) && 
       NullOrCheck(_y, y) && 
       NullOrCheck(_z, z.IsSameAs); 
    } 

變戲法似的 - 一切工作和測試再次通過

回答

4

你可以使用Object.Equals

return NullOrCheck(value, v => object.Equals(v, expected)); 

stringoverloads靜態==運算符來比較它的兩個字符串參數是否相等,即

string first = "abc"; 
string second = "abc"; 

bool eq = first == second; 

==的通話將使用字符串重載==,因爲靜態類型的firstsecond都是string

然而,在

object first = "abc"; 
object second = "abc"; 
bool eq = first == second; 

==操作者使用將是自靜態類型的firstsecond是對象由object定義的一個。請注意,在這種情況下,由於字符串interning,firstsecond實際上將包含對相同字符串的引用,但通常情況並非如此。

在一般方法中,==將解析爲爲object定義的靜態==,而不是爲string定義的更具體的版本。由於==是對object s的簡單參考相等性檢查,因此其行爲有所不同。

Equals方法是虛擬的,可以重寫以專門爲自定義類型進行相等性檢查。因此,在

object first = "abc"; 
object second = "abc"; 
bool eq = first.Equals(second); 

string.Equals方法將被調用,這會檢查,而不是僅僅在相同的附圖中的字符串具有相同的值,。

靜態object.Equals方法使用虛擬Equals實例方法,因此它也將檢查字符串具有相同的值,而不是隻指向相同的字符串實例。靜態object.Equals也檢查其參數爲null,因此比直接調用objA.Equals(objB)更安全。

+0

它似乎也有工作要做:v.Equals(預期)。看起來像一個非常奇怪的修復,因爲你會認爲如果使用較少的派生==,那麼相同的情況對於等於也是如此。或者我在這裏錯過了什麼? – 2013-05-14 12:30:26

+1

@JonnyLeeds - '=='是一個靜態運算符,因此根據其參數的靜態類型進行解析。 「Equals」是一個虛擬方法,在運行時解析。靜態Object.Equals方法也檢查它的參數爲null,所以'Equals(null,someObject)'返回false,而null.Equals(someObject)'在運行時拋出一個異常。 – Lee 2013-05-14 12:34:02

+0

你可以擴展一下 - 我聽說過以前的靜態類型的短語,但沒有正確解釋它。順便說一句,知道內置於Equals中的空檢查 - 大概這意味着你可以進一步簡化這個方法 – 2013-05-14 12:38:15

相關問題