Meine anfängliche Präferenz (aus einem C ++ - Hintergrund) war String.Format. Ich habe dies später aus folgenden Gründen fallen gelassen:
- Die Verkettung von Zeichenfolgen ist wohl "sicherer". Es ist mir passiert (und ich habe gesehen, dass es mehreren anderen Entwicklern passiert ist), einen Parameter zu entfernen oder die Parameterreihenfolge versehentlich durcheinander zu bringen. Der Compiler vergleicht die Parameter nicht mit der Formatzeichenfolge und es kommt zu einem Laufzeitfehler (wenn Sie das Glück haben, ihn nicht in einer undurchsichtigen Methode zu haben, z. B. beim Protokollieren eines Fehlers). Bei der Verkettung ist das Entfernen eines Parameters weniger fehleranfällig. Sie könnten argumentieren, dass die Fehlerwahrscheinlichkeit sehr gering ist, aber es kann vorkommen .
- String-Verkettung erlaubt Nullwerte, String.Format
nicht. Das Schreiben von " s1 + null + s2
" wird nicht unterbrochen, sondern behandelt den Nullwert lediglich als String.Empty. Nun, dies kann von Ihrem spezifischen Szenario abhängen - es gibt Fälle, in denen Sie einen Fehler wünschen, anstatt einen Null-Vornamen stillschweigend zu ignorieren. Aber selbst in dieser Situation bevorzuge ich es persönlich, selbst nach Nullen zu suchen und bestimmte Fehler zu werfen, anstatt der Standard-ArgumentNullException, die ich von String.Format erhalte.
- Die Verkettung von Zeichenfolgen ist besser. Einige der obigen Beiträge erwähnen dies bereits (ohne tatsächlich zu erklären, warum, was mich dazu veranlasste, diesen Beitrag zu schreiben :).
Die Idee ist, dass der .NET-Compiler intelligent genug ist, um diesen Code zu konvertieren:
public static string Test(string s1, int i2, int i3, int i4,
string s5, string s6, float f7, float f8)
{
return s1 + " " + i2 + i3 + i4 + " ddd " + s5 + s6 + f7 + f8;
}
dazu:
public static string Test(string s1, int i2, int i3, int i4,
string s5, string s6, float f7, float f8)
{
return string.Concat(new object[] { s1, " ", i2, i3, i4,
" ddd ", s5, s6, f7, f8 });
}
Was unter der Haube von String.Concat passiert, ist leicht zu erraten (verwenden Sie Reflector). Die Objekte im Array werden über ToString () in ihre Zeichenfolge konvertiert. Dann wird die Gesamtlänge berechnet und nur eine Zeichenfolge zugewiesen (mit der Gesamtlänge). Schließlich wird jede Zeichenfolge über wstrcpy in einem unsicheren Code in die resultierende Zeichenfolge kopiert.
Gründe String.Concat
ist viel schneller? Nun, wir können alle sehen, was String.Format
passiert - Sie werden überrascht sein, wie viel Code für die Verarbeitung der Formatzeichenfolge erforderlich ist. Darüber hinaus (ich habe Kommentare zum Speicherverbrauch gesehen) wird String.Format
intern ein StringBuilder verwendet. Hier ist wie:
StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
Für jedes übergebene Argument werden 8 Zeichen reserviert. Wenn das Argument ein einstelliger Wert ist, haben wir schade Platz verschwendet. Wenn es sich bei dem Argument um ein benutzerdefiniertes Objekt handelt, für das Langtext zurückgegeben wird ToString()
, ist möglicherweise sogar eine Neuzuweisung erforderlich (natürlich im schlimmsten Fall).
Im Vergleich dazu verschwendet die Verkettung nur den Speicherplatz des Objektarrays (nicht zu viel, wenn man bedenkt, dass es sich um ein Array von Referenzen handelt). Es gibt keine Analyse für Formatspezifizierer und keinen zwischengeschalteten StringBuilder. Der Box- / Unboxing-Overhead ist bei beiden Methoden vorhanden.
Der einzige Grund, warum ich mich für String.Format entschieden habe, ist die Lokalisierung. Durch das Einfügen von Formatzeichenfolgen in Ressourcen können Sie verschiedene Sprachen unterstützen, ohne den Code zu beeinträchtigen (denken Sie an Szenarien, in denen formatierte Werte die Reihenfolge je nach Sprache ändern, dh "nach {0} Stunden und {1} Minuten" auf Japanisch möglicherweise ganz anders aussehen: ).
Um meinen ersten (und ziemlich langen) Beitrag zusammenzufassen:
- Der beste Weg (in Bezug auf Leistung vs. Wartbarkeit / Lesbarkeit) für mich ist die Verwendung der Zeichenfolgenverkettung ohne
ToString()
Aufrufe
- Wenn Sie nach der Aufführung sind,
ToString()
rufen Sie selbst an, um das Boxen zu vermeiden (ich bin etwas voreingenommen gegenüber der Lesbarkeit) - genau wie bei der ersten Option in Ihrer Frage
- Wenn Sie dem Benutzer lokalisierte Zeichenfolgen anzeigen (hier nicht der Fall),
String.Format()
hat dies eine Kante.