2014-10-30 27 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) ...可能是最有效的。

相关问题