.NET字符串真的应该被认为是不可变的吗?

Jam*_* Ko 9 .net c# string immutability

请考虑以下代码:

unsafe
{
    string foo = string.Copy("This can't change");

    fixed (char* ptr = foo)
    {
        char* pFoo = ptr;
        pFoo[8] = pFoo[9] = ' ';
    }

    Console.WriteLine(foo); // "This can   change"
}
Run Code Online (Sandbox Code Playgroud)

这将创建一个指向第一个字符的指针,将其foo重新指定为变为可变,并将字符8和9的位置更改为' '.

注意我从未真正重新分配过foo; 相反,我通过修改其状态或改变字符串来改变其值.因此,.NET字符串是可变的.

这样做效果很好,事实上,以下代码:

unsafe
{
    string bar = "Watch this";

    fixed (char* p = bar)
    {
        char* pBar = p;
        pBar[0] = 'C';
    }

    string baz = "Watch this";
    Console.WriteLine(baz); // Unrelated, right?
}
Run Code Online (Sandbox Code Playgroud)

将打印"Catch this"由于字符串文字实习.

这有很多适用的用途,例如:

string GetForInputData(byte[] inputData)
{
    // allocate a mutable buffer...
    char[] buffer = new char[inputData.Length];

    // fill the buffer with input data

    // ...and a string to return
    return new string(buffer);
}
Run Code Online (Sandbox Code Playgroud)

被替换为:

string GetForInputData(byte[] inputData)
{
    // allocate a string to return
    string result = new string('\0', inputData.Length);

    fixed (char* ptr = result)
    {
        // fill the result with input data
    }

    return result; // return it
}
Run Code Online (Sandbox Code Playgroud)

如果您在速度关键领域(例如编码)工作,这可以节省潜在的巨大内存分配/性能成本.

我猜你可以说这不算数,因为它"使用hack"来使指针变得可变,但是再一次是C#语言设计者支持首先将字符串赋值给指针.(事实上,这样做是所有 时间在内部StringStringBuilder,所以在技术上你可以使自己的StringBuilder与此有关.)

那么,.NET字符串真的应该被认为是不可变的吗?

drf*_*drf 6

§18#C#语言规范(fixed语句)专门解决了通过固定指针修改字符串的情况,并指出这样做会导致未定义的行为:

通过固定指针修改托管类型的对象可能导致未定义的行为.例如,因为字符串是不可变的,所以程序员有责任确保不修改指向固定字符串的指针引用的字符.