下面的代码是如何打印的true?
string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x,y));
Run Code Online (Sandbox Code Playgroud)
我希望这会打印False,因为我希望构造两个单独的对象,然后比较它们的引用。
这是 CLR 中未记录的(据我所知)优化。这很奇怪,但是是的:new操作符从两个调用中返回相同的引用。
它似乎在 CoreCLR 以及 Linux(甚至在 Mono)上实现。
字符串构造函数是我见过的唯一示例,尽管如注释中所述,您可以使用其他构造函数重载来激发它。
我确信这是 CLR 中的优化,因为 IL 就像您所期望的那样 - 将构造函数调用移动到不同的方法中也不会改变事情:
using System;
public class Test
{
static void Main()
{
// Declaring as object to avoid using the == overload in string
object x = CreateString(new char[0]);
object y = CreateString(new char[0]);
object z = CreateString(new char[1]);
Console.WriteLine(x == y); // True
Console.WriteLine(x == z); // False
}
static string CreateString(char[] c)
{
return new string(c);
}
}
Run Code Online (Sandbox Code Playgroud)
现在 CLR 是开源的,我们可以找出执行此操作的位置。它似乎在object.cpp- 如果您搜索出现的次数,GetEmptyString您会看到它在构造长度为 0 的字符串时在各种情况下使用。
发生这种情况是因为特殊情况是从空字符数组构造空字符串。字符串构造函数返回string.Empty以这种方式构造的空字符串:
string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x, y)); // true
Console.WriteLine(object.ReferenceEquals(x, string.Empty)); // true
Run Code Online (Sandbox Code Playgroud)
[System.Security.SecurityCritical] // auto-generated
private unsafe String CtorCharPtr(char *ptr)
{
if (ptr == null)
return String.Empty;
#if !FEATURE_PAL
if (ptr < (char*)64000)
throw new ArgumentException(Environment.GetResourceString("Arg_MustBeStringPtrNotAtom"));
#endif // FEATURE_PAL
Contract.Assert(this == null, "this == null"); // this is the string constructor, we allocate it
try {
int count = wcslen(ptr);
if (count == 0)
return String.Empty;
String result = FastAllocateString(count);
fixed (char *dest = result)
wstrcpy(dest, ptr, count);
return result;
}
catch (NullReferenceException) {
throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
}
}
Run Code Online (Sandbox Code Playgroud)
而且(这是char[]参数的构造函数):
[System.Security.SecuritySafeCritical] // auto-generated
private String CtorCharArray(char [] value)
{
if (value != null && value.Length != 0) {
String result = FastAllocateString(value.Length);
unsafe {
fixed (char * dest = result, source = value) {
wstrcpy(dest, source, value.Length);
}
}
return result;
}
else
return String.Empty;
}
Run Code Online (Sandbox Code Playgroud)
请注意以下几行:
if (count == 0)
return String.Empty;
Run Code Online (Sandbox Code Playgroud)
和
else
return String.Empty;
Run Code Online (Sandbox Code Playgroud)