简体   繁体   English

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

[英]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: 实际上,对于字符串来说,实际上只有两种特殊情况表现出类似于您在此处描述的行为:

  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). 空字符串是一个特别奇怪的情况,据我所知,.NET程序中的每个空字符串实际上都是同一个对象(即“每个空字符串”构成一个字符串)。 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. 这是我在.NET中唯一知道的情况,其中使用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.

相关问题 为什么两个单独的字符串引用相等? 换句话说,为什么s和t都是相同的引用? - Why are 2 separate string references equal? In other words why are s and t both the same reference? 创建对字符串的引用 (Blazor) - create a reference to an string (Blazor) C#Linq-如果输入不等于任何字符串[] - C# Linq - If input is not equal to any of the string[] 集合中是否有任何项与特定字符串相等 - Is there any item in a collection that is equal to a specific string 除了性能和可读性之外,为什么System.String是引用类型而不是值类型还有其他原因吗? - Is there any other reason beside performance and readiblity of why System.String is a reference type instead of value type? 将字符串与数据库中的字符串进行比较将返回false - Comparing a string to it's equal in a database returns false 可能的 null 参数“s”在“double double.Parse(string s)”中解析的参考参数 - possible null reference argument for parameter 's' parse in 'double double.Parse(string s)' 不等字符串 - Not equal string 是否可以从String创建VisualBrush? - Is it possible to create VisualBrush from String? 我们只是创建一个字符串类的引用而不创建对象,然后开始使用它,这怎么可能? - We just create a reference of string class without making a object of it and start using it, how is it possible?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM