Rozważmy następujący kod:Czy ciągi .NET naprawdę powinny być uważane za niezmienne?
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"
}
Stwarza to wskaźnik do pierwszego znaku foo
, przypisuje go stać zmienny i zmienia znaki 8 i 9 pozycji w górę do ' '
.
Uwaga Nigdy właściwie nie przypisano foo
; zamiast tego zmieniłem jego wartość modyfikując jej stan lub mutujący łańcuch. Dlatego ciągi .NET są zmienne.
To działa tak dobrze, w rzeczywistości, że następujący kod:
unsafe
{
string bar = "Watch this";
fixed (char* p = bar)
{
char* pBar = p;
pBar[0] = 'C';
}
string baz = "Watch this";
Console.WriteLine(baz); // Unrelated, right?
}
wypisze "Catch this"
powodu strun dosłownym internowania.
ta ma wiele zastosowań, stosowanych na przykład w ten sposób:
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);
}
zostaje zastąpiony przez:
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
}
To może zaoszczędzić potencjalnie ogromne koszty alokacji pamięci/wydajność, jeśli pracujesz w Speed- pole krytyczne (np. kodowanie).
Myślę, że można powiedzieć, że to się nie liczy, ponieważ "używa hacka", aby wskaźniki były zmienne, ale znowu to projektanci języka C#, którzy w pierwszej kolejności wspierali przypisywanie łańcucha do wskaźnika. (W rzeczywistości, to odbywa allthetime wewnętrznie String
i StringBuilder
, więc technicznie można zrobić własny StringBuilder z tym.)
Tak, należy NET ciągi naprawdę uznać niezmienne?
Są one niezmienne w przypadku korzystania z publicznego interfejsu API. Jeśli używasz niebezpiecznego kodu lub odbicia, aby ominąć ten publiczny interfejs API, nie jest. – MarcinJuraszek
@MarcinJuraszek Wskaźniki * są * częścią publicznego interfejsu API, zobacz także mój ostatni akapit. –
Mówię o publicznym API klasy 'string' - o metodach, właściwościach, które eksponuje. – MarcinJuraszek