Betrachten wir den folgenden Code:Sollten .NET-Strings wirklich als unveränderlich betrachtet werden?
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"
}
dies ein Zeiger auf das erste Zeichen des foo
erzeugt, neu zuweist es wandelbar zu werden, und ändert die Zeichen 8 und 9-Positionen bis ' '
.
Hinweis Ich habe nie wirklich neu zugewiesen foo
; stattdessen änderte ich seinen Wert, indem ich seinen Zustand änderte, oder muting die Zeichenfolge. Daher sind .NET-Zeichenfolgen veränderbar.
Das funktioniert so gut, in der Tat, dass der folgende Code:
unsafe
{
string bar = "Watch this";
fixed (char* p = bar)
{
char* pBar = p;
pBar[0] = 'C';
}
string baz = "Watch this";
Console.WriteLine(baz); // Unrelated, right?
}
"Catch this"
aufgrund Stringliteral interning gedruckt wird.
Dies hat viel anwendbar verwendet zum Beispiel dieses:
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
}
Dies könnte sparen Speicherzuweisung/Leistungskosten potenziell große, wenn Sie in einem drehzahl- arbeiten:
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);
}
ersetzt wird kritisches Feld (z. B. Kodierungen).
Ich denke, Sie könnten sagen, dass dies nicht zählt, weil es "einen Hack verwendet", um Zeiger änderbar zu machen, aber wiederum waren es die C# -Sprachdesigner, die die Zuweisung eines Strings zu einem Zeiger an erster Stelle unterstützten. (In der Tat ist dieser allthetime intern getan in String
und StringBuilder
, so technisch könnten Sie Ihren eigenen String mit dieser machen.)
So soll .NET wirklich Strings unveränderlich angesehen werden?
Sie sind bei Verwendung der öffentlichen API unveränderlich. Wenn Sie unsicheren Code oder eine falsche Reflexion verwenden, um diese öffentliche API zu umgehen, sind sie es nicht. – MarcinJuraszek
@MarcinJuraszek Zeiger * sind * Teil der öffentlichen API, siehe auch meinen letzten Absatz. –
Ich spreche über öffentliche API der 'string' Klasse - die Methoden, Eigenschaften, die es zur Verfügung stellt. – MarcinJuraszek