【发布时间】:2019-08-29 08:06:42
【问题描述】:
string 在 C# 中是一种引用类型,其行为类似于值类型。通常程序员不必担心这一点,因为字符串是不可变的,并且语言设计可以防止我们对它们做无意的危险事情。但是,使用不安全的指针逻辑是否可以直接操作字符串的底层值,如下所示:
class Program
{
static string foo = "FOO";
static string bar = "FOO";
const string constFoo = "FOO";
static unsafe void Main(string[] args)
{
fixed (char* p = foo)
{
for (int i = 0; i < foo.Length; i++)
p[i] = 'M';
}
Console.WriteLine($"foo = {foo}"); //MMM
Console.WriteLine($"bar = {bar}"); //MMM
Console.WriteLine($"constFoo = {constFoo}"); //FOO
}
}
运行时,编译器将优化(实习)字符串,使foo 和bar 都指向相同的底层值。通过以这种方式操作foo,我们还可以更改bar 的值。 const 值由编译器内联,不受此影响。到目前为止没有什么奇怪的。
让我们将固定变量从foo 更改为constFoo,我们开始看到一些奇怪的行为。
class Program
{
static string foo = "FOO";
static string bar = "FOO";
const string constFoo = "FOO";
static unsafe void Main(string[] args)
{
fixed (char* p = constFoo)
{
for (int i = 0; i < constFoo.Length; i++)
p[i] = 'M';
}
Console.WriteLine($"foo = {foo}"); //MMM
Console.WriteLine($"bar = {bar}"); //MMM
Console.WriteLine($"constFoo = {constFoo}"); //FOO
}
}
尽管我们修复和操作了 constFoo,但它的值 foo 和 bar 发生了变异。
为什么foo 和bar 会发生变异?
如果我们现在改变foo 和bar 的值,那就更奇怪了。
class Program
{
static string foo = "BAR";
static string bar = "BAR";
const string constFoo = "FOO";
static unsafe void Main(string[] args)
{
fixed (char* p = constFoo)
{
for (int i = 0; i < constFoo.Length; i++)
p[i] = 'M';
}
Console.WriteLine($"foo = {foo}"); //BAR
Console.WriteLine($"bar = {bar}"); //BAR
Console.WriteLine($"constFoo = {constFoo}"); //FOO
}
}
代码运行,我们似乎在某处发生了变异,但我们的变量没有变化。 我们在这段代码中改变了什么?
【问题讨论】:
-
因为你没有变异
constFoo。你正在改变它指向的字符串,它恰好是实习生表中的一个字符串。 -
这与前一周的this question 相似(尽管不一定重复)。
-
部分混淆可能是您将字符串视为值类型,而您的意思是它们是 variable-length 引用类型,仍然是引用类型,通过和通过。