“Object.ReferenceEquals”始终是假的,因为它是带一个值类型
当我使用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?
对于字符串是否要使用Equals
或ReferenceEquals
似乎有争议。 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
作为字符串值。
然后对我来说,应该使用特定于您比较的对象而不是Object.Equals()或Object.ReferenceEquals()的'Equals()'扩展。 – 2014-10-30 21:23:18
@CodeMaverick右 - 理想情况下,你会使用类型特定的重写(或静态版本'string.Equals(string,string)')。但是我们谈论的是自动生成的代码,毕竟... – McGarnagle 2014-10-30 21:26:47
正确...与问题相关,它是自动生成的代码,但我自私地想知道哪个是首选的,因为并非所有自动生成的代码可以或应该被认为是“最佳实践”。 – 2014-10-30 22:19:36
@McGarnagle
然而,由于字符串实习,等效字符串字面量会出来为相同的参考
字符串并不总是拘留。为了实现,字符串值需要在编译时知道。 I.E只有字符串文字,并且在那里连接。 也有不同的.NET运行时版本/版本的实习。 埃里克利珀,谁在C#编译器团队在微软,写了一篇关于这个问题,请参阅:"String interning and String.Empty" Sept 2009
至于比较两个字符串值平等。
if (String.CompareOrdinal (strA, strB) != 0) ...
可能是最有效的。
表达式Equals(this.CategoryField,value)'如何编译?在哪里得到'Equals()'方法?至于更大的问题,这听起来像是一个ReSharper错误。 System.String显然不是一个值类型,所以虽然使用'this.CategoryField.Equals(value)'而不是'object.ReferenceEquals()'可能更好,但具体的投诉Resharper似乎不是有效的。 – 2014-10-30 19:38:03
它编译得很好。它是'Object.Equals()'。 – 2014-10-30 19:48:46
啊,谢谢。我忘记了那个方法的静态版本。咄。无论如何,我仍然认为你正在查看一个Resharper错误。 – 2014-10-30 20:27:55