Possible inadvertent comparative comparison

I have code similar to the following:

this.Session[key] = "foo"; if ((this.Session[key] ?? string.Empty) == "foo") { //do stuff } 

This, of course, creates the situation "Possible unintentional comparison of links made for the intended purpose." The solution to this is well documented here, and I already knew that the fix was to pass the session variable to string as soon as I saw the code.

However, the year code never changed since it was originally written. Until this week, in our test environment, the if was evaluated as true and executed the //do stuff section. This erroneous code STILL WORKS, as provided for in our production environment.

How can it be? There is no reason why this code, as written, should ever work as intended; and yet he did it and still does in production. And what would have changed so that this code, which should not have worked, but did, suddenly stops working (or, rather, behave the way it should always be)?

+6
source share
2 answers

The string literal "foo" is interned . This means that every time it is used, it refers to the same object.

The common language environment maintains a string repository by maintaining a table called a cross-domain pool that contains a single reference to each line of a unique literal declared or created programmatically in your program. Therefore, an instance of a literal string with a specific value exists only once in the system.

For example, if you assign the same literal string to multiple variables, the runtime gets the same literal string reference from the pool and assigns it to each variable.

This is why object.ReferenceEquals("foo", "foo") true.

If you do the same with a dynamically created string, it will not be interned and the links will not be equal

 object str = new StringBuilder().Append("f").Append("oo").ToString(); // str = "foo" object.ReferenceEquals(str, "foo"); // false 

Interpreting strings can work differently depending on the implementation, so when comparing strings by reference, you can distinguish between different environments.

+4
source

You are fortunate that the comparison worked! In your example, the string "foo" is interned , that is, both string literals are stored once and have the same reference. However, if one of the two foo is defined in another assembly or de-serialized or somehow constructed in the code (for example, string s = "f"; string t = s + "oo"; ), then the links may be different. Since the Session[key] is typed as an object, a reference comparison will be performed.

Merging is not required, however casting:

 if ((string)Session[key] == "foo") { ... } // This will perform a textual comparison. 

You can also write this (since Equals is polymorphic):

 if (Session[key].Equals("foo")) { ... } // This will perform a textual comparison. 

It is not enough to compare 2 string values, they need to be statically entered as string to compare as strings.

A related, extremely interesting Jon Skeet post on this topic: fooobar.com/questions/33918 / ...

+2
source

All Articles