';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

';Object.ReferenceEquals';总是false,因为它是用值类型调用的

对于字符串使用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可能是最有效的。