繁体   English   中英

是否可以创建一个不是引用的字符串 - 等于任何其他字符串?

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

似乎.NET不再通过引用使值相等的字符串。

在LINQPad中,我尝试了以下内容,希望它绕过内部字符串常量:

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

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

但这会返回true 不过,我想创建一个string这是其他任何可靠的区分string对象。

(用例是创建一个用于可选参数的sentinel值。我正在包装WebForms的Page.Validate() ,我想根据调用者是否给我提供可选的验证组参数来选择适当的重载。所以我希望能够检测调用者是否省略了该参数,或者他是否传递了一个恰好等于我的默认值的值。显然,还有其他不那么神秘的方法来处理这个特定的用例,这个问题的目的更多跑位。)

似乎.NET不再通过引用使值相等的字符串。

实际上,对于字符串来说,实际上只有两种特殊情况表现出类似于您在此处描述的行为:

  1. 代码中的字符串文字是实体的,因此两个地方的相同文字将导致对同一对象的引用。
  2. 空字符串是一个特别奇怪的情况,据我所知,.NET程序中的每个空字符串实际上都是同一个对象(即“每个空字符串”构成一个字符串)。 这是我在.NET中唯一知道的情况,其中使用new关键字(在类上)可能不会导致分配新对象。

根据您的问题,我得到您已经了解的第一个案例的印象。 第二种情况是你偶然发现的那种情况。 正如其他人指出的那样,如果你只是继续使用非空字符串,你会发现创建一个非引用的字符串很容易 - 等于程序中的任何其他字符串:

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

除了一点点编辑之外,我实际上并不介意这么多(只要记录在案); 但有点让我感到不安的是,CLR人员(?)实现了这种优化,而没有继续前进并为数组做同样的事情。 也就是说,在我看来,他们也可能继续前进并使每个new T[0]引用同一个对象。 或者,你知道,也没有为字符串做过。

如果字符串是ReferenceEqual,则它们是同一个对象。 当你调用new string(new char[0]) ,你没有得到恰好是引用的新对象 - 等于string.Empty; 那是不可能的。 相反,您将获得对已创建的string.Empty实例的新引用。 这是字符串构造函数中特殊情况代码的结果。

尝试这个:

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

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

另外,请注意字符串常量是实例化的,因此代码中文字"Ab"所有实例都将彼此相等,因为它们都引用相同的字符串对象。 常数折叠也适用,因此常量表达式"A" + "b"也将等于"Ab"

因此,您的sentinal值可以是私有创建的非零长度字符串。

您可以将不可打印的字符放入字符串...甚至是0 / nul字符。 但实际上,我只是使用null作为sentinel值,并尝试确保其他地方的代码使用空字符串而不是null。

所以我希望能够检测调用者是否省略了该参数,或者是否传递了一个恰好等于我的默认值的值。

我之前从未这样做过,但我的想法是制作一个Nullable类......但是它不是Nullable而是Parameter并且会跟踪它是否已被赋值(包括null )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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