为什么修改这个字符串也会修改另一个单独的字符串的内容?
Why is modifying this String also modifying the content of another, seperate String?
在我的静态 main
函数中,我有以下代码:
string str1 = "aaaaaaaaa";
pointerTest();
Console.WriteLine( "str1 is: " + str1 );
声明为 unsafe
的静态 pointerTest
方法包含以下内容:
string str2 = "aaaaaaaaa";
fixed( char* ptr = str2 )
{
for( int i = 0; i < str2.Length / 3; ++i )
ptr[i] = 'z';
}
Console.WriteLine( "str2 is: " + str2 );
请注意 str1
和 str2
是如何独立声明的,但确实具有相同的内容。
该程序的预期输出将是:
str2 is: zzzaaaaaa
str1 is: aaaaaaaaa
当我运行程序实际输出显示如下:
str2 is: zzzaaaaaa
str1 is: zzzaaaaaa
当我将 str2
或 str1
更改为不具有完全相同的内容时(例如,在 [=18 的末尾添加一个 'a' =]) 程序按预期运行。
如果发现此行为同时存在于 .Net Core 3.1 和 Mono 中(不确定确切版本,我使用 Repl.It)
我的问题是为什么会发生这种行为以及可以采取什么措施来解决它。
我的理论是,这是因为 编译器优化 ,特别是一个名为 string interning:
的过程
编译器认识到没有必要自行分配 str2
,因为内存中已经存在完全相同的 chars 序列,并随初始化分配str1
个。因此,它没有重新分配它,而是使 str2
成为 str1
已经指向的位置的引用。有关更多信息,请阅读 here.
字符串 在 C# 中被认为是不可变的,因此 - 在正常情况下 - 不应该以任何方式、形状或形式修改它们的内容。
由于此代码使用了 unsafe
关键字和 pointer-logic,因此不能保证不会导致 未定义的行为,从而导致令人惊讶的结果。
解决这个“问题”的唯一方法是遵守 C# 规范并将 Strings 视为不可变的。
在我的静态 main
函数中,我有以下代码:
string str1 = "aaaaaaaaa";
pointerTest();
Console.WriteLine( "str1 is: " + str1 );
声明为 unsafe
的静态 pointerTest
方法包含以下内容:
string str2 = "aaaaaaaaa";
fixed( char* ptr = str2 )
{
for( int i = 0; i < str2.Length / 3; ++i )
ptr[i] = 'z';
}
Console.WriteLine( "str2 is: " + str2 );
请注意 str1
和 str2
是如何独立声明的,但确实具有相同的内容。
该程序的预期输出将是:
str2 is: zzzaaaaaa
str1 is: aaaaaaaaa
当我运行程序实际输出显示如下:
str2 is: zzzaaaaaa
str1 is: zzzaaaaaa
当我将 str2
或 str1
更改为不具有完全相同的内容时(例如,在 [=18 的末尾添加一个 'a' =]) 程序按预期运行。
如果发现此行为同时存在于 .Net Core 3.1 和 Mono 中(不确定确切版本,我使用 Repl.It)
我的问题是为什么会发生这种行为以及可以采取什么措施来解决它。
我的理论是,这是因为 编译器优化 ,特别是一个名为 string interning:
的过程编译器认识到没有必要自行分配 str2
,因为内存中已经存在完全相同的 chars 序列,并随初始化分配str1
个。因此,它没有重新分配它,而是使 str2
成为 str1
已经指向的位置的引用。有关更多信息,请阅读 here.
字符串 在 C# 中被认为是不可变的,因此 - 在正常情况下 - 不应该以任何方式、形状或形式修改它们的内容。
由于此代码使用了 unsafe
关键字和 pointer-logic,因此不能保证不会导致 未定义的行为,从而导致令人惊讶的结果。
解决这个“问题”的唯一方法是遵守 C# 规范并将 Strings 视为不可变的。