Einleitung: Warum das Verbinden von Strings nicht einfach "Zusammenfügen" ist
\n\nStellen Sie sich vor: Sie schreiben einen Webdienst in C#, der eine Liste von Tags vom Benutzer entgegennimmt und diese als einen einzigen, kommagetrennten String an die Datenbank senden muss. Oder Sie erstellen einen CSV-Bericht für den Export. Oder Sie protokollieren eine Reihe von IDs. Eine vertraute Situation? Die Frage "Creating a comma separated list from IList
Es scheint so einfach: Man nehme eine Liste von Strings, durchlaufe sie in einer Schleife und füge Kommas hinzu. Aber in der Praxis birgt diese Aufgabe mehrere Fallstricke: von überflüssigen Kommas am Ende bis hin zu katastrophalen Leistungseinbußen bei großen Datenmengen. In diesem Artikel zeigen wir nicht nur fertige Lösungen, sondern werfen einen Blick unter die Haube jeder einzelnen. Sie erfahren, wie string.Join, StringBuilder und sogar LINQ Aggregate funktionieren, und lernen, das richtige Werkzeug für Ihre Aufgabe auszuwählen.
Los geht's!
\n\nDas Problem: Eine einfache Anfrage, nicht offensichtliche Schwierigkeiten
\n\nAngenommen, wir haben eine Sammlung von Strings:
\n\nIEnumerable<string> fruits = new List<string> { "Apple", "Banana", "Cherry", "Date" };\n\nWir möchten erhalten: "Apple,Banana,Cherry,Date". Das Erste, was einem Anfänger in den Sinn kommt, ist eine Schleife zu schreiben:
string result = "";\nbool first = true;\nforeach (var fruit in fruits)\n{\n if (!first)\n result += ",";\n result += fruit;\n first = false;\n}\n\nDieser Code funktioniert, aber er tut dies schrecklich. Warum? Weil Strings in C# unveränderlich sind. Jede +=-Operation erzeugt einen neuen String im Speicher und kopiert den Inhalt des vorherigen hinein. Bei 4 Elementen ist das nicht spürbar, aber bei 10.000 Strings erhalten Sie eine quadratische Komplexität O(n²) und einen gigantischen Speicherverbrauch. Unter der Haube bedeuten das tausende Allokationen und Garbage Collections.
Offensichtlich ist ein klügerer Ansatz nötig. Und hier betreten die Hauptdarsteller die Bühne.
\n\nMethode 1: string.Join – der König der Leistung
\n\nDer korrekteste und leistungsfähigste Weg ist die Verwendung der statischen Methode string.Join:
string csv = string.Join(",", fruits);\nConsole.WriteLine(csv); // Apple,Banana,Cherry,Date\n\nEine Zeile Code – und die Sache ist erledigt. Werfen wir einen Blick unter die Haube von string.Join (in .NET Core / .NET 5+).
Was passiert im Inneren?
\n- \n
- Längenberechnung: Die Methode durchläuft zunächst die gesamte Sammlung (wenn es sich um ein
IEnumerable<T>handelt), um die Gesamtanzahl der Zeichen zu ermitteln. Wenn die Sammlung ein Array oder eineIListist, erhält sie die Länge sofort überCount. \n - Pufferzuweisung: Ein großer Zeichen-Array (
char[]) mit der benötigten Größe wird zugewiesen: Summe der Längen aller Strings + (Anzahl der Strings - 1) * Länge des Trennzeichens. \n - Kopieren: Alle Strings und Trennzeichen werden ohne eine einzige überflüssige Allokation in diesen Puffer kopiert. \n
- String-Erstellung: Aus dem Puffer wird ein einziger finaler String erstellt. \n
Ergebnis: Eine Speicherallokation (für den endgültigen String) + Allokation des temporären Puffers. Keine Zwischenstrings. Die Komplexität ist strikt O(n).
\n\nFür IList<string> arbeitet die Methode noch schneller, da sie sofort Count und die Länge jedes Elements über den Indexer abrufen kann, ohne GetEnumerator aufrufen zu müssen.
Methode 2: StringBuilder – ein alter Freund
\n\nVor dem Aufkommen des optimierten string.Join (oder wenn Sie an einer alten Version des .NET Framework festhängen) war die Standardlösung StringBuilder:
var sb = new StringBuilder();\nbool first = true;\nforeach (var fruit in fruits)\n{\n if (!first)\n sb.Append(',');\n sb