简体   繁体   中英

Is it possible to create a string that's not reference-equal to any other string?

It seems like .NET goes out of its way to make strings that are equal by value equal by reference.

In LINQPad, I tried the following, hoping it'd bypass interning string constants:

var s1 = new string("".ToCharArray());
var s2 = new string("".ToCharArray());

object.ReferenceEquals(s1, s2).Dump();

but that returns true . However, I want to create a string that's reliably distinguishable from any other string object.

(The use case is creating a sentinel value to use for an optional parameter. I'm wrapping WebForms' Page.Validate() , and I want to choose the appropriate overload depending on whether the caller gave me the optional validation group argument. So I want to be able to detect whether the caller omitted that argument, or whether he passed a value that happens to be equal to my default value. Obviously there's other less arcane ways of approaching this specific use case, the aim of this question is more academical.),

It seems like .NET goes out of its way to make strings that are equal by value equal by reference.

Actually, there are really only two special cases for strings that exhibit behavior like what you're describing here:

  1. String literals in your code are interned, so the same literal in two places will result in a reference to the same object.
  2. The empty string is a particularly weird case, where as far as I know literally every empty string in a .NET program is in fact the same object (ie, "every empty string" constitutes a single string). This is the only case I know of in .NET where using the new keyword (on a class) may potentially not result in the allocation of a new object.

From your question I get the impression you already knew about the first case. The second case is the one you've stumbled across. As others have pointed out, if you just go ahead and use a non-empty string, you'll find it's quite easy to create a string that isn't reference-equal to any other string in your program:

public static string Sentinel = new string(new char[] { 'x' });

As a little editorial aside, I actually wouldn't mind this so much (as long as it were documented); but it kind of irks me that the CLR folks (?) implemented this optimization without also going ahead and doing the same for arrays. That is, it seems to me they might as well have gone ahead and made every new T[0] refer to the same object too. Or, you know, not done that for strings either.

If the strings are ReferenceEqual, they are the same object. When you call new string(new char[0]) , you don't get a new object that happens to be reference-equal to string.Empty; that would be impossible. Rather, you get a new reference to the already-created string.Empty instance. This is a result of special-case code in the string constructor.

Try this:

var s1 = new string(new char { 'A', 'b' });
var s2 = new string(new char { 'A', 'b' });

object.ReferenceEquals(s1, s2).Dump();

Also, beware that string constants are interned, so all instances of the literal "Ab" in your code will be reference equal to one another, because they all refer to the same string object. Constant folding applies, too, so the constant expression "A" + "b" will also be reference equal to "Ab" .

Your sentinal value, therefore, can be a privately-created non-zero-length string.

You can put non-printable characters into the string... even the 0/nul character. But really, I'd just use null for the sentinel value, and try to ensure code elsewhere is using the empty string instead of null.

So I want to be able to detect whether the caller omitted that argument, or whether he passed a value that happens to be equal to my default value.

I've never done this before, but my thoughts would be to make a Nullable class... but instead of Nullable it would be Parameter and would keep track on whether or not it has been assigned anything (including null ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM