[英]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. 似乎.NET不再通过引用使值相等的字符串。
In LINQPad, I tried the following, hoping it'd bypass interning string constants: 在LINQPad中,我尝试了以下内容,希望它绕过内部字符串常量:
var s1 = new string("".ToCharArray());
var s2 = new string("".ToCharArray());
object.ReferenceEquals(s1, s2).Dump();
but that returns true
. 但这会返回
true
。 However, I want to create a string
that's reliably distinguishable from any other string
object. 不过,我想创建一个
string
这是其他任何可靠的区分string
对象。
(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.), (用例是创建一个用于可选参数的sentinel值。我正在包装WebForms的
Page.Validate()
,我想根据调用者是否给我提供可选的验证组参数来选择适当的重载。所以我希望能够检测调用者是否省略了该参数,或者他是否传递了一个恰好等于我的默认值的值。显然,还有其他不那么神秘的方法来处理这个特定的用例,这个问题的目的更多跑位。)
It seems like .NET goes out of its way to make strings that are equal by value equal by reference.
似乎.NET不再通过引用使值相等的字符串。
Actually, there are really only two special cases for strings that exhibit behavior like what you're describing here: 实际上,对于字符串来说,实际上只有两种特殊情况表现出类似于您在此处描述的行为:
new
keyword (on a class) may potentially not result in the allocation of a new object. new
关键字(在类上)可能不会导致分配新对象。 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.
但有点让我感到不安的是,CLR人员(?)实现了这种优化,而没有继续前进并为数组做同样的事情。 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. 也就是说,在我看来,他们也可能继续前进并使每个
new T[0]
引用同一个对象。 Or, you know, not done that for strings either. 或者,你知道,也没有为字符串做过。
If the strings are ReferenceEqual, they are the same object. 如果字符串是ReferenceEqual,则它们是同一个对象。 When you call
new string(new char[0])
, you don't get a new object that happens to be reference-equal to string.Empty; 当你调用
new string(new char[0])
,你没有得到恰好是引用的新对象 - 等于string.Empty; that would be impossible. 那是不可能的。 Rather, you get a new reference to the already-created string.Empty instance.
相反,您将获得对已创建的string.Empty实例的新引用。 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. 另外,请注意字符串常量是实例化的,因此代码中文字
"Ab"
所有实例都将彼此相等,因为它们都引用相同的字符串对象。 Constant folding applies, too, so the constant expression "A" + "b"
will also be reference equal to "Ab"
. 常数折叠也适用,因此常量表达式
"A" + "b"
也将等于"Ab"
。
Your sentinal value, therefore, can be a privately-created non-zero-length string. 因此,您的sentinal值可以是私有创建的非零长度字符串。
You can put non-printable characters into the string... even the 0/nul character. 您可以将不可打印的字符放入字符串...甚至是0 / nul字符。 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. 但实际上,我只是使用
null
作为sentinel值,并尝试确保其他地方的代码使用空字符串而不是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
). 我之前从未这样做过,但我的想法是制作一个
Nullable
类......但是它不是Nullable
而是Parameter
并且会跟踪它是否已被赋值(包括null
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.