Ich fürchte, das ist eine sehr dumme Frage, aber mir muss etwas fehlen.
Warum möchte man vielleicht String.Copy (string) verwenden ?
Die Dokumentation sagt die Methode
Erstellt eine neue Instanz von String mit demselben Wert wie ein angegebener String.
Da Zeichenfolgen in .NET unveränderlich sind, bin ich mir nicht sicher, welchen Nutzen diese Methode hat, da ich das denke
string copy = String.Copy(otherString);
würde für alle praktischen Zwecke das gleiche Ergebnis liefern wie
string copy = otherString;
Das heißt, abgesehen von der internen Buchhaltung und der Tatsache, dass das Kopieren nicht ReferenceEquals
auf otherString erfolgt, gibt es keine beobachtbaren Unterschiede. String ist eine unveränderliche Klasse, deren Gleichheit auf Wert und nicht auf Identität basiert. (Dank an @Andrew Hare für den Hinweis, dass meine ursprüngliche Formulierung nicht präzise genug war, um anzuzeigen, dass ich einen Unterschied zwischen Copy
ing und nicht erkannte , aber besorgt über den wahrgenommenen Mangel an nützlichem Unterschied war.)
Wenn ein null
Argument übergeben wird, löst Copy natürlich ein aus ArgumentNullException
, und die "neue Instanz" verbraucht möglicherweise mehr Speicher. Letzteres scheint kaum ein Vorteil zu sein, und ich bin mir nicht sicher, ob der Null-Check groß genug ist, um eine vollständige Kopiermethode zu rechtfertigen.
Vielen Dank.
quelle
Antworten:
Mit
String.Copy
ordnen Sie tatsächlich neuen Speicher zu und kopieren die Zeichen von einer Zeichenfolge in eine andere. Sie erhalten eine völlig neue Instanz, anstatt dass beide Variablen dieselbe Instanz sind. Dies kann von Bedeutung sein, wenn Sie die Zeichenfolge mit nicht verwaltetem Code verwenden, der sich direkt mit den Speicherorten befasst und die Zeichenfolge mutieren kann.quelle
Hier ist ein Teil des Puzzles. Es erklärt nicht, warum Sie es tun möchten, aber es hilft, einen funktionalen Unterschied zu erklären.
Wenn Sie die Zeichenfolge mit dem
fixed
Schlüsselwort anheften, kann der Inhalt geändert werden. Ich kann mir keine Situation vorstellen, in der Sie dies tun möchten, aber es ist möglich.string original = "Hello World"; string refCopy = original; string deepCopy = String.Copy(original); fixed(char* pStr = original) { *pStr = 'J'; } Console.WriteLine(original); Console.WriteLine(refCopy); Console.WriteLine(deepCopy);
Ausgabe:
quelle
String.Copy
gibt ein neues zurückString
und liefert nicht die gleichen Ergebnisse wieString copy = otherString;
Versuche dies:
using System; class Program { static void Main() { String test = "test"; String test2 = test; String test3 = String.Copy(test); Console.WriteLine(Object.ReferenceEquals(test, test2)); Console.WriteLine(Object.ReferenceEquals(test, test3)); Console.ReadLine(); } }
Wenn Sie
test2 = test
diese Referenzen festlegen, verweisen Sie auf dasselbeString
. DieCopy
Funktion gibt eine neueString
Referenz zurück, die denselben Inhalt hat, jedoch als anderes Objekt auf dem Heap.Bearbeiten: Es gibt viele Leute, die ziemlich verärgert sind, dass ich die Frage des OP nicht beantwortet habe. Ich glaube, dass ich die Frage beantwortet habe, indem ich eine falsche Prämisse in der Frage selbst korrigiert habe. Hier ist eine analoge (wenn nicht zu vereinfachte) Frage und Antwort, die hoffentlich meinen Standpunkt verdeutlicht:
Frage:
Antworten:
In diesem Beispiel könnten Sie argumentieren, dass die Antwort nicht wirklich eine Antwort ist, da die Frage lautete: "Was ist der Zweck der Beifahrertür?". Aber da diese Frage ausschließlich auf einem Missverständnis der Funktionsweise der Türen beruhte, folgt daraus nicht, dass die Widerlegung der Prämisse durch Abzug neues Licht auf den Zweck der anderen Tür werfen wird?
quelle
Eine schnelle Suche in der BCL nach .NET 4.0 zeigt, dass die
string.Copy
Methode an etwa einem halben Dutzend Stellen aufgerufen wird. Die Verwendungen fallen in ungefähr diese Kategorien:Für die Interaktion mit nativen Funktionen, die die an sie übergebenen Zeichenfolgen beschädigen können. Wenn Sie die P / Invoke-Deklaration nicht beeinflussen und die aufgerufene Funktion nicht reparieren können,
string.Copy
ist dies die beste Wahl.Für Situationen, in denen die Zeichenfolge aus Leistungsgründen direkt geändert wird. Wenn Sie nur wenige Zeichen in einer möglicherweise langen Zeichenfolge in Kleinbuchstaben konvertieren müssen, können Sie dies nur tun, ohne die Zeichenfolge zweimal zu kopieren und zusätzlichen Müll zu erstellen, indem Sie sie mutieren.
An Orten, an denen es nicht notwendig erscheint. Es ist durchaus möglich, dass einige Programmierer eher an Java- oder C ++ - Zeichenfolgen gewöhnt sind und nicht erkennen, dass das Kopieren einer Zeichenfolge in C # selten nützlich ist.
quelle
string a = "abc"; string b = String.Copy(a); Monitor.Enter(a); // not the same as Monitor.Enter(b);
jedoch
string c = "123"; string d = c; Monitor.Enter(c); // the same as Monitor.Enter(d);
Ich denke, es ist der Vollständigkeit halber so, wie es irgendjemand interessieren wird.
Ebenfalls
StringBuilder sb = new StringBuilder(100); sb.Append("abc"); string a = sb.ToString(); string b = String.Copy(a);
Ich denke
a
, dann wird mehr RAM belegtb
, daa
auf den Puffer der Größe 100 verwiesen wird, den derStringBuilder
erstellt hat. (Schauen Sie sich das Innere derStringBuilder.ToString()
Methode an.)Ich denke,
StringBuilder
dass die Verwendung desString.Copy()
.NET-FrameworksStringBuilder
den Inhalt des .NET-Frameworks verändertstring
. Astring
ist also nicht immer unveränderlich.quelle
Zusätzlich zu dem, was tvanfosson gesagt hat (ich glaube nicht, dass Sie über nicht verwalteten Code auf den von einer verwalteten Zeichenfolge verwendeten Puffer zugreifen können ... Ich weiß, dass es zumindest schwierig wäre), glaube ich, dass es einen Unterschied geben kann, wenn die Zeichenfolge ist Wird als Objekt zum Sperren der Multithread-Funktionalität verwendet.
Zum Beispiel...
using System; public class Class1 { string example1 = "example"; string example2 = example1; public void ExampleMethod1() { lock (example1) { Console.WriteLine("Locked example 1"); //do stuff... } } public void ExampleMethod2() { lock (example2) { Console.WriteLine("Locked example 2"); //do stuff } } }
Ich glaube, wenn die beiden Beispielmethoden parallel ausgeführt werden, sperren sie dasselbe Objekt und daher kann eine nicht ausgeführt werden, während sich die andere in ihrem Sperrblock befindet.
Wenn Sie es jedoch ändern ...
using System; public class Class1 { string example1 = "example"; string example2 = string.Copy(example1); public void ExampleMethod1() { lock (example1) { Console.WriteLine("Locked example 1"); //do stuff... } } public void ExampleMethod2() { lock (example2) { Console.WriteLine("Locked example 2"); //do stuff } } }
Dann glaube ich, dass sie nur die Ausführung anderer Threads blockieren, die dieselbe Methode ausführen (dh alle Threads, die ExampleMethod1 ausführen, werden gesperrt, bis jeder abgeschlossen ist, aber sie werden Threads, die ExampleMethod2 ausführen, nicht stören).
Ich bin mir nicht sicher, ob dies ein nützlicher Unterschied ist, da es bessere Mechanismen für die Synchronisation gibt (ich denke nicht, dass das Sperren von Zeichenfolgen eine sehr gute Idee ist).
quelle
string a = "test"; string b = a; //Object.ReferenceEquals(a,b) is true a += "more"; //Object.ReferenceEquals(a,b) is now false !
Auto-Change-Erkennung?
quelle
Ich bin nicht sicher, wie String in .NET implementiert wird, aber ich denke, Java ist eine gute Referenz.
In Java macht new String (str) auch was String.copy (str); Weisen Sie einen neuen String mit demselben Wert zu.
Es scheint nutzlos, aber es ist sehr nützlich bei der Speicheroptimierung.
String enthält ein char [] mit Offset und Länge in der Implementierung. Wenn Sie so etwas wie einen Teilstring ausführen, wird keine Speicherkopie erstellt, sondern eine neue String-Instanz zurückgegeben, die dasselbe Zeichen [] verwendet. In vielen Fällen spart dieses Muster viel Speicherkopie und Zuordnung. Wenn Sie jedoch ein kleines Stück innerhalb eines langen großen Strings unterteilen. Es wird immer noch auf großes Zeichen [] verwiesen, selbst wenn der ursprüngliche große String GC sein kann.
String longString = // read 1MB text from a text file String memoryLeak = largeString.substring(100,102); largeString=null; // memoryLeak will be sized 1MB in the memory String smaller = new String(largeString.substring(100,102)); // smaller will be only few bytes in the memory
Es kann das neue String-Objekt zwingen, sein eigenes Zeichen [] zuzuweisen, um versteckte Speicherverluste / -verschwendung zu verhindern.
quelle