Si consideri il seguente codice:Le stringhe .NET potrebbero essere considerate immutabili?
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"
}
Questo crea un puntatore al primo carattere di foo
, riassegna a diventare mutabile, e modifica i caratteri 8 e 9 posizioni fino a ' '
.
Avviso In realtà non ho mai riassegnato foo
; invece, ho cambiato il suo valore modificando il suo stato, o mutando la stringa. Pertanto, le stringhe .NET sono modificabili.
Questo funziona così bene, infatti, che il seguente codice:
unsafe
{
string bar = "Watch this";
fixed (char* p = bar)
{
char* pBar = p;
pBar[0] = 'C';
}
string baz = "Watch this";
Console.WriteLine(baz); // Unrelated, right?
}
stamperà "Catch this"
a causa di stringa internato letterale.
Questo ha un sacco di usi applicabili, ad esempio questo:
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);
}
viene sostituito da:
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
}
Questo potrebbe salvare potenzialmente enormi costi di allocazione della memoria/prestazioni se si lavora in un velocità- campo critico (ad es. codifiche).
Immagino si possa dire che questo non conta perché "usa un hack" per rendere i puntatori mutabili, ma poi di nuovo sono stati i progettisti di linguaggio C# che hanno supportato l'assegnazione di una stringa a un puntatore in primo luogo. (In realtà, questo è fatto allthetime internamente nel String
e StringBuilder
, quindi tecnicamente si può fare il vostro proprio StringBuilder con questo.)
Quindi, dovrebbe NET stringhe davvero essere considerati immutabili?
Sono immutabili quando si utilizza l'API pubblica. Se si utilizza codice o riflessione non sicuri per ignorare tale API pubblica non lo sono. – MarcinJuraszek
@MarcinJuraszek I puntatori * sono * parte dell'API pubblica, vedi anche il mio ultimo paragrafo. –
Sto parlando dell'API pubblica della classe 'string' - i metodi, le proprietà che espone. – MarcinJuraszek