2014-10-30 53 views
1

當我使用SlSvcUtil.exe創建我的服務客戶端文件,我看到這樣的代碼:「Object.ReferenceEquals」始終是假的,因爲它是帶一個值類型

private string CategoryField; 

[System.Runtime.Serialization.DataMemberAttribute()] 
public string Category 
{ 
    get 
    { 
     return this.CategoryField; 
    } 
    set 
    { 
     if ((object.ReferenceEquals(this.CategoryField, value) != true)) 
     { 
      this.CategoryField = value; 
      this.RaisePropertyChanged("Category"); 
     } 
    } 
} 

當我檢查它ReSharper的,我收到以下警告:

「Object.ReferenceEquals」始終是假的,因爲它是帶一個值類型

據我所知,strings are immutable,但我似乎收到每個屬性的警告。

ReSharper的提出以下建議:

注:這包括將簡單的getter在一行,倒置if,去除多餘的object預選賽和!= true比較我的自定義樣式

private string CategoryField; 

[DataMember] 
public string Category 
{ 
    get { return this.CategoryField; } 
    set 
    { 
     if (Equals(this.CategoryField, value)) { return; } 

     this.CategoryField = value; 
     this.RaisePropertyChanged("Category"); 
    } 
} 

所以它真的會提出這樣的問題,爲什麼SlSvcUtil.exe使用ReferenceEquals而不是Equals if ReferenceEquals總是會返回false?

+2

表達式Equals(this.CategoryField,value)'如何編譯?在哪裏得到'Equals()'方法?至於更大的問題,這聽起來像是一個ReSharper錯誤。 System.String顯然不是一個值類型,所以雖然使用'this.CategoryField.Equals(value)'而不是'object.ReferenceEquals()'可能更好,但具體的投訴Resharper似乎不是有效的。 – 2014-10-30 19:38:03

+0

它編譯得很好。它是'Object.Equals()'。 – 2014-10-30 19:48:46

+0

啊,謝謝。我忘記了那個方法的靜態版本。咄。無論如何,我仍然認爲你正在查看一個Resharper錯誤。 – 2014-10-30 20:27:55

回答

2

對於字符串是否要使用EqualsReferenceEquals似乎有爭議。 Equals將比較字符串的值,而ReferenceEquals將比較引用 - 但是,由於字符串interning,等價的字符串文字將作爲相同的引用出現。例如:

static void Main(string[] args) 
    { 
     string x = "hi", y = "hi", z = string.Concat('h', 'i'); 
     Console.WriteLine(ReferenceEquals(x, y)); // true 
     Console.WriteLine(ReferenceEquals(x, z)); // false 

     Console.WriteLine(Equals(x, y)); // true 
     Console.WriteLine(Equals(x, z)); // true 

     Console.ReadLine(); 
    } 

那麼代碼生成算法的作者是如何決定的?一對夫婦考慮我能想到的:

  • 性能:Object.Equals需要一個虛擬方法調用,這是比靜態Object.ReferenceEquals(考慮可能不太高性能的,我們正在談論的字符串,其引用類型不需要拳擊)。
  • 通常情況下你會希望使用ReferenceEquals作爲引用類型 - 作者可能已經決定不需要爲字符串的特殊情況維護單獨的代碼。
  • 還請注意,在此特定情況下使用ReferenceEquals防禦性選擇。使用ReferenceEquals確保在以上情況#2中應用setter,而在此情況下使用Equals而不是應用setter。你可能會想到一些角落的情況,後者的行爲可能會引入一個非常難以察覺的錯誤。

無論如何,Resharper警告顯然是錯誤的。 String是一個引用類型,而不是值類型,並且(如上例所示)ReferenceEquals實際上可以返回true作爲字符串值。

+0

然後對我來說,應該使用特定於您比較的對象而不是Object.Equals()或Object.ReferenceEquals()的'Equals()'擴展。 – 2014-10-30 21:23:18

+0

@CodeMaverick右 - 理想情況下,你會使用類型特定的重寫(或靜態版本'string.Equals(string,string)')。但是我們談論的是自動生成的代碼,畢竟... – McGarnagle 2014-10-30 21:26:47

+0

正確...與問題相關,它是自動生成的代碼,但我自私地想知道哪個是首選的,因爲並非所有自動生成的代碼可以或應該被認爲是「最佳實踐」。 – 2014-10-30 22:19:36

1

@McGarnagle

然而,由於字符串實習,等效字符串字面量會出來爲相同的參考

字符串並不總是拘留。爲了實現,字符串值需要在編譯時知道。 I.E只有字符串文字,並且在那裏連接。 也有不同的.NET運行時版本/版本的實習。 埃裏克利珀,誰在C#編譯器團隊在微軟,寫了一篇關於這個問題,請參閱:"String interning and String.Empty" Sept 2009

至於比較兩個字符串值平等

if (String.CompareOrdinal (strA, strB) != 0) ...可能是最有效的。

相關問題