Становится ли StringBuilder неизменным после вызова ToString?

Я отчетливо помню с первых дней существования .NET, что вызов ToString в StringBuilder использовался для предоставления нового строкового объекта (который должен быть возвращен) с внутренним буфером символов, используемым StringBuilder. Таким образом, если вы создали огромную строку с помощью StringBuilder, вызов ToString не должен был ее копировать.

При этом StringBuilder должен был предотвратить любые дополнительные изменения в буфере, потому что теперь он использовался неизменной строкой. В результате StringBuilder переключился бы на «копирование при изменении», при котором любая попытка изменения сначала создаст новый буфер, скопирует в него содержимое старого буфера и только затем изменит его.

Я думаю, это предположение заключался в том, что StringBuilder будет использоваться для создания строки, затем преобразован в обычную строку и отброшен. Мне кажется, что это разумное предположение.

Вот в чем дело. Я не могу найти упоминания об этом в документации. Но я не уверен, что это когда-либо было задокументировано.

Итак, я посмотрел на реализацию ToString с использованием Reflector (.NET 4.0), и мне кажется, что он действительно копирует строку, а не просто разделяет буфер:

[SecuritySafeCritical]
public override unsafe string ToString()
{
    string str = string.FastAllocateString(this.Length);
    StringBuilder chunkPrevious = this;
    fixed (char* str2 = ((char*) str))
    {
        char* chPtr = str2;
        do
        {
            if (chunkPrevious.m_ChunkLength > 0)
            {
                char[] chunkChars = chunkPrevious.m_ChunkChars;
                int chunkOffset = chunkPrevious.m_ChunkOffset;
                int chunkLength = chunkPrevious.m_ChunkLength;
                if ((((ulong) (chunkLength + chunkOffset)) > str.Length) ||     (chunkLength > chunkChars.Length))
                {
                    throw new ArgumentOutOfRangeException("chunkLength",     Environment.GetResourceString("ArgumentOutOfRange_Index"));
                }
                fixed (char* chRef = chunkChars)
                {
                    string.wstrcpy(chPtr + chunkOffset, chRef, chunkLength);
                }
            }
            chunkPrevious = chunkPrevious.m_ChunkPrevious;
        }
        while (chunkPrevious != null);
    }
    return str;
}

Теперь, как я уже упоминал ранее, я отчетливо помню, как читал, что это имело место в первые дни существования .NET. Я даже нашел упоминание в этой книге .

Мой вопрос: было ли это поведение отброшено? Если да, то кто-нибудь знает почему? Для меня это имело смысл ...

15
задан Colin Cochrane 12 November 2010 в 15:32
поделиться