';Object.ReferenceEquals';总是false,因为它是用值类型调用的
本文关键字:调用 类型 ReferenceEquals Object 总是 false 因为 | 更新日期: 2023-09-27 18:28:33
当我使用SlSvcUtil.exe创建服务客户端文件时,我看到的代码如下:
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"总是false,因为它是用值类型调用的
我知道字符串是不可变的,但我似乎收到了每个属性的警告。
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");
}
}
因此,这确实引出了一个问题,如果ReferenceEquals
总是返回false,为什么SlSvcUtil.exe使用ReferenceEquals
而不是Equals
?
对于字符串使用Equals
还是ReferenceEquals
似乎存在争议。Equals
将比较字符串的值,而ReferenceEquals
将比较引用——然而,由于字符串内部化,等效的字符串文字将显示为相同的引用。例如:
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
。
@McGarnagle
然而,由于字符串内部,等价的字符串文字将作为相同的引用出现
字符串并不总是固定的。为了进行intered,字符串值需要在编译时已知。I.E只有字符串文字,并且存在串联。对于.NET运行时的不同版本/构建,也有不同的内部处理。Eric Lippert是微软C#编译器团队的成员,他写过关于这个问题的文章,请参阅:"String interning和String.Empty"2009年9月
至于比较值相等的两个字符串。
CCD_ 20可能是最有效的。