62341

'Object.ReferenceEquals' is always false because it is called with a value type

When I use <strong>SlSvcUtil.exe</strong> to create my service client files, I see code like this:

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");
        }
    }
}


When I inspect it with <strong>ReSharper</strong>, I receive the following warning:

'Object.ReferenceEquals' is always false because it is called with a value type

I understand that strings are immutable, but I seem to receive this warning for every property.

<strong>ReSharper</strong> recommends the following:

Note: This includes my custom styling of putting simple getters on one line, inverting the if, removing the redundant object qualifier and the != true comparison

private string CategoryField;

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

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


So it really begs the question, why does <strong>SlSvcUtil.exe</strong> use ReferenceEquals instead of Equals if ReferenceEquals is always going to return false?

Answer1:

It seems debatable whether you would want to use Equals or ReferenceEquals for strings. Equals will compare the values of the strings, whereas ReferenceEquals will compare references -- however, due to string interning, equivalent string literals will come out as the same reference. For example:

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(); }

So how did the authors of the code generation algorithm decide? A couple of considerations I can think of:

    <li>Performance: Object.Equals requires a virtual method call, which is likely less performant than the static Object.ReferenceEquals (given that we are talking about strings, which as reference types do not require boxing).</li> <li>Normally you would want to use ReferenceEquals for reference types -- the authors may have decided that it was not worth maintaining separate code for the special case of strings.</li> <li>Note also that using ReferenceEquals is the defensive choice in this specific instance. Using ReferenceEquals ensures that the setter is applied in case #2 above, whereas using Equals would not apply the setter in that case. You could probably dream up some corner case where the latter behavior could introduce a very hard-to-detect bug.</li> </ul>

    Anyway, the Resharper warning is clearly wrong. String is a reference type, not a value type, and (as demonstrated in the above example) ReferenceEquals can in fact return true for string values.

    Answer2:

    @McGarnagle

    however, due to string interning, equivalent string literals will come out as the same reference

    strings are not always interned. In order to be interned, the string value needs be known at compile time. I.E only string literals and there concatenations are interned. Also there is varying interning for different versions / builds of the .NET runtime. Eric Lippert, who was on the C# compiler team at Microsoft, wrote about this issue, see: "String interning and String.Empty" Sept 2009

    As for comparing two strings for value equality.

    if (String.CompareOrdinal (strA, strB) != 0) ... is likely the most efficient.

Recommend

  • What is the canonical way to convert a MethodDeclarationSyntax to a ConstructorDeclarationSyntax?
  • Does Aegir 3+ support both D7 and D8 deployments
  • How can I bind a factory to a annotation-qualified injection point?
  • Excel & Powershell: Bulk Find and replace URL's used in formulas
  • Display database item with DataSet to Datagridview from separated class to winform
  • DataContract surrogate for amplified value type
  • ObservableCollection and CollectionChanged event as WCF datacontract
  • How to use SpEL to inject result of method call in Spring?
  • SQL Server 2008R2 and creating XML document
  • Learn Ruby Hard Way ex. 48
  • Continuous movement of a box in pygame
  • How to set repeating alarm using setExact and how to cancel the same?
  • Mutate value by using a value from a different row in a tibble
  • Original method still getting called in Moq even after CallBase = true/false
  • EntityDataSource query inner join
  • Unable to retrieve number before incoming call in marshmallow
  • Compare variables PHP
  • ValidationResult Returned From IValidatableObject.Validate Is Not Localized
  • Set cookie from Web Api 2 IAuthenticationFilter AuthenticateAsync method
  • Comma within fields in CSV file -import to DB using SSIS
  • Regex: Match everything except backreference
  • Get Users in Group from Azure AD via Microsoft Graph
  • Why == is different for Integer and String?
  • Where should I store a file in Android?
  • Dynamically generated lookup key for IQueryable
  • How to fail Phing without triggering backtrace
  • Linq Full Outer Join on Two Objects
  • How to get the index of element in the List in c#
  • Insert records if not exist SQL Server 2005
  • SonarQube: Cannot deactivate rule with missing quality profile
  • How to detect interior vertices in groups of 2d polygons? (E.g. ZIP Codes to determine a territory)
  • Remove changes from one element when event occurs on another element?
  • Remove final comma from string in vb.net
  • Time complexity of a program which involves multiple variables
  • Xamarin Forms - UWP Fonts
  • Regex thinks I'm nesting, but I'm not
  • Arrow is showed instead of the material design version hamburger icon. Why doesn't syncState in
  • Large data - storage and query
  • Arrays break string types in Julia
  • git trying to push non-existent file … after clearing cache