Pamiętam od samego początku .NET, że wywoływanie ToString na StringBuilderze służyło do dostarczania nowego obiektu napisów (do zwrócenia) z wewnętrznym buforem znaków używanym przez StringBuilder. W ten sposób, jeśli skonstruowałeś ogromny ciąg za pomocą StringBuilder, wywołanie ToString nie musiało go kopiować.Czy StringBuilder staje się niezmienny po wywołaniu ToString?
W ten sposób StringBuilder musiał zapobiec wszelkim dodatkowym zmianom w buforze, ponieważ był używany przez niezmienny ciąg. W rezultacie StringBuilder przełączy się na "copy-on-change", gdzie każda próba zmiany spowoduje najpierw utworzenie nowego bufora, skopiowanie zawartości starego bufora i tylko jego zmianę.
Sądzę, że założono, że StringBuilder zostanie użyty do skonstruowania łańcucha znaków, a następnie przekształcony na zwykły ciąg znaków i odrzucony. Wydaje mi się rozsądnym założeniem.
Teraz o to chodzi. Nie mogę znaleźć żadnej wzmianki o tym w dokumentacji. Ale nie jestem pewien, czy kiedykolwiek został udokumentowany.
Więc spojrzał na realizację ToString użyciu reflektor (.NET 4.0) i wydaje mi się, że to rzeczywiście kopie napisu, a nie tylko dzielić bufor:
[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;
}
Teraz, jak ja wspomniano wcześniej, wyraźnie pamiętam, że przeczytałem, że tak było na początku, jeśli .NET. Znalazłem nawet wzmiankę o tym book.
Moje pytanie brzmi, czy to zachowanie zostało usunięte? Jeśli tak, to nikt nie wie, dlaczego? To miało dla mnie sens ...
Interesujące. Ciąg jest przechowywany jako seria char [] s. Ale nie ma linii "chunkPrevious = chunkPrevious.m_ChunkPrevious;" sugeruje, że te tablice są przechowywane w oddzielnych instancjach StringBuilder, powiązanych jako lista połączona, wewnętrznie w instancji StringBuilder, do której mamy odnośnik? – Sorax