Frage

Lassen Sie uns sagen, die Sie ausgeben möchten, oder concat strings.Welche der folgenden Stile bevorzugst du?

  • var p = new { FirstName = "Bill", LastName = "Gates" };

  • Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

  • Console.WriteLine(p.FirstName + " " + p.LastName);

Tun Sie stattdessen verwenden-format oder machen Sie einfach concat von strings?Was ist Ihr Favorit?Einer von diesen zu verletzen Ihre Augen?

Haben Sie irgendwelche rationalen Argumente zu verwenden, die eine und nicht die andere?

Ich würde mich für das zweite.

War es hilfreich?

Lösung

Versuchen Sie diesen code.

Es ist eine leicht modifizierte version Ihres Codes.
1.Ich entfernte Konsole.WriteLine wie es wahrscheinlich einige Größenordnungen langsamer als das, was ich bin versucht zu Messen.
2.Ich bin die Stoppuhr gestartet wird, bevor die Schleife und beenden Sie es nach rechts, so befinde ich mich nicht zu verlieren Präzision, wenn die Funktion nimmt zum Beispiel 26.4 Zecken zu führen.
3.Die Art und Weise Sie teilte das Ergebnis durch einige Iterationen falsch war.Sehen Sie, was passiert, wenn Sie 1000 Millisekunden und 100 Millisekunden.In beiden Fällen erhalten Sie 0 ms nach Division durch 1000000.

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (p.FirstName + " " + p.LastName);
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();
s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", p.FirstName, p.LastName);
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();


Console.Clear();
Console.WriteLine(n.ToString()+" x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Thread.Sleep(4000);

Das sind meine Ergebnisse:

1000000 x result = string.Format("{0} {1}", p.FirstName, p."LastName");nahmen:618ms - 2213706 Zecken
1000000 x result = (p.FirstName + "" + p."LastName");nahmen:166ms - 595610 Zecken

Andere Tipps

Ich bin erstaunt, dass so viele Menschen sofort wollen, finden Sie den code, der ausgeführt wird, am schnellsten. Wenn EINE MILLION Iterationen NOCH dauern weniger als eine Sekunde zu verarbeiten, ist das in IRGENDEINER WEISE bemerkbar zu die Ende Benutzer?Nicht sehr wahrscheinlich.

Vorzeitige Optimierung = nicht ausreichend.

Ich würde gehen mit der String.Format option, nur weil es am meisten Sinn macht, von einem architektonischen Standpunkt aus.I don ' T care über die Leistung, bis es ein Problem wird (und wenn es das täte, würde ich mich Fragen:Tun ich müssen, um zu verketten einer Millionen Namen auf einmal?Sicherlich werden Sie nicht alle auf den Bildschirm passen,...)

Überlegen Sie, ob Ihr Kunde will später zu ändern, so dass Sie können konfigurieren, ob die Anzeige "Firstname Lastname" oder "Lastname, Firstname." Mit der option Format, das ist einfach - nur swap heraus die format-string.Mit der concat, müssen Sie zusätzlichen code.Sicher, das klingt nicht wie eine große Sache, in diesem besonderen Beispiel, aber extrapolieren.

Ach ja, nach der Lektüre einer der anderen Antworten, die ich versuchte die Umkehrung der Reihenfolge der Operationen - also die Durchführung der Verkettung zuerst, dann den String.Format...

Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 8ms - 30488 ticks
Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 0ms - 182 ticks

So ist die Reihenfolge der Operationen macht einen RIESIGEN Unterschied, oder vielmehr die erste operation ist IMMER viel langsamer.

Hier die Ergebnisse von laufen, in denen Operationen sind abgeschlossen, mehr als einmal.Ich habe versucht, die änderung der Bestellungen, aber die Dinge sind im Allgemeinen die gleichen Regeln, sobald das erste Ergebnis ignoriert wird:

Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 5ms - 20335 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 156 ticks
Bill Gates
Console.WriteLine(FirstName + " " + LastName); took: 0ms - 122 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 181 ticks
Bill Gates
Console.WriteLine("{0} {1}", FirstName, LastName); took: 0ms - 122 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 142 ticks
Bill Gates
String.Concat(FirstName, " ", LastName); took: 0ms - 117 ticks

Wie Sie sehen können nachfolgende Läufe mit der gleichen Methode (ich Refactoring den code in 3-Methoden) sind inkrementell schneller.Der Schnellste erscheint die Konsole.WriteLine(String.Concat (...)) - Methode, gefolgt von normalen Verkettung, und dann die formatierte Operationen.

Die anfängliche Verzögerung bei der Inbetriebnahme ist wahrscheinlich der Initialisierung der Konsole aus Streamen, wie das stellen einer Konsole.Writeline("Start!") vor dem ersten Betrieb bringt alle mal zurück in die Reihe.

Strings sind unveränderlich, das heißt den gleichen winzigen Teil des Speichers verwendet wird, über und über in Ihrem code.Hinzufügen die gleichen zwei strings zusammen und schaffen die gleiche neue string über und über wieder nicht Auswirkungen Speicher..Net ist smart genug, nur verwenden den gleichen Speicher verweisen.Daher ist der code nicht wirklich testen der Unterschied zwischen den beiden Methoden concat.

Versuchen Sie, diese für Größe:

Stopwatch s = new Stopwatch();

int n = 1000000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0, sbElapsedMilliseconds = 0, sbElapsedTicks = 0;

Random random = new Random(DateTime.Now.Millisecond);

string result;
s.Start();
for (var i = 0; i < n; i++)
    result = (random.Next().ToString() + " " + random.Next().ToString());
s.Stop();
cElapsedMilliseconds = s.ElapsedMilliseconds;
cElapsedTicks = s.ElapsedTicks;
s.Reset();

s.Start();
for (var i = 0; i < n; i++)
    result = string.Format("{0} {1}", random.Next().ToString(), random.Next().ToString());
s.Stop();
fElapsedMilliseconds = s.ElapsedMilliseconds;
fElapsedTicks = s.ElapsedTicks;
s.Reset();

StringBuilder sb = new StringBuilder();
s.Start();
for(var i = 0; i < n; i++){
    sb.Clear();
    sb.Append(random.Next().ToString());
    sb.Append(" ");
    sb.Append(random.Next().ToString());
    result = sb.ToString();
}
s.Stop();
sbElapsedMilliseconds = s.ElapsedMilliseconds;
sbElapsedTicks = s.ElapsedTicks;
s.Reset();

Console.WriteLine(n.ToString() + " x result = string.Format(\"{0} {1}\", p.FirstName, p.LastName); took: " + (fElapsedMilliseconds) + "ms - " + (fElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x result = (p.FirstName + \" \" + p.LastName); took: " + (cElapsedMilliseconds) + "ms - " + (cElapsedTicks) + " ticks");
Console.WriteLine(n.ToString() + " x sb.Clear();sb.Append(random.Next().ToString()); sb.Append(\" \"); sb.Append(random.Next().ToString()); result = sb.ToString(); took: " + (sbElapsedMilliseconds) + "ms - " + (sbElapsedTicks) + " ticks");
Console.WriteLine("****************");
Console.WriteLine("Press Enter to Quit");
Console.ReadLine();

Beispiel-Ausgabe:

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 513ms - 1499816 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 393ms - 1150148 ticks
1000000 x sb.Clear();sb.Append(random.Next().ToString()); sb.Append(" "); sb.Append(random.Next().ToString()); result = sb.ToString(); took: 405ms - 1185816 ticks

Schade, daß die Armen übersetzer

Wenn Sie weiß Ihre Anwendung wird bleiben in Englisch, dann in Ordnung, speichern Sie die Uhr tickt.Jedoch, viele Kulturen sehen in der Regel Lastname Firstname, zum Beispiel Adressen.

So verwenden Sie string.Format(), vor allem, wenn du gehst, immer haben Ihre Anwendung überall, dass Englisch nicht die erste Sprache ist.

Hier sind meine Ergebnisse über 100.000 Iterationen:

Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took (avg): 0ms - 689 ticks
Console.WriteLine(p.FirstName + " " + p.LastName); took (avg): 0ms - 683 ticks

Und hier ist die Bank code:

Stopwatch s = new Stopwatch();

var p = new { FirstName = "Bill", LastName = "Gates" };

//First print to remove the initial cost
Console.WriteLine(p.FirstName + " " + p.LastName);
Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

int n = 100000;
long fElapsedMilliseconds = 0, fElapsedTicks = 0, cElapsedMilliseconds = 0, cElapsedTicks = 0;

for (var i = 0; i < n; i++)
{
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();
    cElapsedMilliseconds += s.ElapsedMilliseconds;
    cElapsedTicks += s.ElapsedTicks;
    s.Reset();
    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    fElapsedMilliseconds += s.ElapsedMilliseconds;
    fElapsedTicks += s.ElapsedTicks;
    s.Reset();
}

Console.Clear();

Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took (avg): " + (fElapsedMilliseconds / n) + "ms - " + (fElapsedTicks / n) + " ticks");
Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took (avg): " + (cElapsedMilliseconds / n) + "ms - " + (cElapsedTicks / n) + " ticks");

Also, ich weiß nicht, wessen Antwort auf mark als Antwort :)

Die Verkettung von strings ist schön, in einem einfachen Szenario, wie es ist mehr kompliziert mit etwas komplizierter, als dass auch LastName, FirstName.Mit dem format, das Sie sehen auf einen Blick, was die endgültige Struktur der string wird beim Lesen der code, mit Verkettung, wird es fast unmöglich, sofort zu erkennen, mit dem Endergebnis (außer mit einem sehr einfachen Beispiel wie diesem).

Was bedeutet, dass in die lange laufen ist, dass, wenn Sie kommen zurück, um änderungen an dem format-string, den man entweder haben die Fähigkeit, pop-in und ein paar Anpassungen vornehmen, um den format-string, oder Falten auf Ihrer Stirn und anfangen sich zu bewegen, um alle Arten von property-Accessoren gemischt mit text, die eher zu Problemen führen.

Wenn Sie Sie verwenden .NET 3.5 können Sie eine Erweiterungsmethode wie diese und erhalten Sie einen leicht fließend, aus dem Stegreif eine syntax wie die folgende:

string str = "{0} {1} is my friend. {3}, {2} is my boss.".FormatWith(prop1,prop2,prop3,prop4);

Schließlich, wie Ihre Anwendung wächst in Komplexität können Sie entscheiden, dass sanely pflegen strings in Ihrer Anwendung, die Sie verschieben wollen Sie in einer Ressource-Datei zu lokalisieren oder einfach nur in eine statische Hilfsmethode.Dies wird VIEL einfacher zu erreichen, wenn Sie konsequent verwendet-Formate, und Ihr code kann ganz einfach umgestaltet werden, etwas zu verwenden wie

string name = String.Format(ApplicationStrings.General.InformalUserNameFormat,this.FirstName,this.LastName);

Für sehr einfache manipulation, die ich verwenden würde, Verkettung, aber sobald man über 2 oder 3 Elemente-Format wird angemessener IMO.

Ein weiterer Grund bevorzugen String.- Format ist, dass .NET-Zeichenfolgen unveränderlich sind, und tun es auf diese Weise erzeugt weniger temporäre/intermediate kopiert.

Während ich völlig verstehen, den Stil und den Vorlieben abgeholt Verkettung für meine erste Antwort zum Teil auf meine eigene Präferenz ist, ein Teil meiner Entscheidung beruhte auf dem Gedanken, dass die Verkettung würde schneller sein.So, aus Neugier habe ich es getestet und die Ergebnisse waren erschütternd, besonders für einen so kleinen string.

Mit dem folgenden code:

    System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();

    var p = new { FirstName = "Bill", LastName = "Gates" };

    s.Start();
    Console.WriteLine("{0} {1}", p.FirstName, p.LastName);
    s.Stop();
    Console.WriteLine("Console.WriteLine(\"{0} {1}\", p.FirstName, p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

    s.Reset();
    s.Start();
    Console.WriteLine(p.FirstName + " " + p.LastName);
    s.Stop();

    Console.WriteLine("Console.WriteLine(p.FirstName + \" \" + p.LastName); took: " + s.ElapsedMilliseconds + "ms - " + s.ElapsedTicks + " ticks");

Ich erhielt die folgenden Ergebnisse:

Bill Gates
Console.WriteLine("{0} {1}", p.FirstName, p.LastName); took: 2ms - 7280 ticks
Bill Gates
Console.WriteLine(p.FirstName + " " + p.LastName); took: 0ms - 67 ticks

Mit der Formatierung Methode ist über 100-mal langsamer!!Verkettung gar nicht registrieren als 1 MS, die ist, warum ich die Ausgabe der timer-ticks als gut.

Für basic-string-Verkettung, die ich verwenden in der Regel die zweite style - leichter zu Lesen und einfacher.Jedoch, wenn ich eine kompliziertere string Kombination, die ich in der Regel entscheiden sich für die Zeichenfolge.Format.

String.Format spart viel Zitate und Pluspunkte...

Console.WriteLine("User {0} accessed {1} on {2}.", user.Name, fileName, timestamp);
vs
Console.WriteLine("User " + user.Name + " accessed " + fileName + " on " + timestamp + ".");

Nur ein paar charicters gespeichert, aber ich denke, in diesem Beispiel, format macht es viel sauberer.

Ein besserer test wäre zu beobachten, Ihre Speicher mit Perfmon und die CLR-Speicher Zähler.Mein Verständnis ist, dass der ganze Grund, warum Sie wollen, verwenden Sie String.Format anstatt nur die Verkettung von strings ist, da strings unveränderlich sind, sind Sie unnötig zu belasten, die den garbage-collector mit temporären strings müssen zurückgefordert werden Sie in den nächsten Durchgang.

StringBuilder und String.Format, obwohl möglicherweise langsamer, mehr Speicher effizient.

Was ist so schlimm daran, die string-Verkettung?

Im Allgemeinen bevorzuge ich die ehemalige, vor allem, wenn die Zeichenketten lang, es kann viel leichter sein, zu Lesen.

Der andere Vorteil ist, glaube ich, eine Leistung, als das letztere tatsächlich durchführt, 2 string-Erstellung-Anweisungen vor der übergabe der endgültigen Zeichenfolge an die Konsole.Write-Methode.String.- Format verwendet ein StringBuilder-Objekt unter der Decke, ich glaube, so mehrere Verkettungen vermieden werden.

Es sollte jedoch beachtet werden, dass, wenn der Parameter, den Sie übergeben, in den String.Format (und andere solche Methoden wie die Konsole.Schreiben) sind value-Typen, dann werden Sie, boxed, bevor Sie übergeben werden, die eigene Leistung hat. Blog-Beitrag dazu finden Sie hier.

Eine Woche von jetzt Aug 19, 2015, diese Frage wird genau sieben (7) Jahre alt.Es gibt jetzt einen besseren Weg, dies zu tun. Besser in Bezug auf die Wartbarkeit, da ich noch nicht zum performance-test im Vergleich zu nur die Verkettung von strings (aber es ist egal, in diesen Tagen?ein paar Millisekunden Unterschied?).Die neue Art, es zu tun mit C# 6.0:

var p = new { FirstName = "Bill", LastName = "Gates" };
var fullname = $"{p.FirstName} {p.LastName}";

Diese neue Funktion ist besser, IMO, und eigentlich besser, in unserem Fall wir haben codes, wo wir bauen, Abfragezeichenfolgen, deren Werte hängt von einigen Faktoren ab.Stellen Sie sich eine querystring-wo haben wir 6 Argumente.Also anstatt das zu tun ein, zum Beispiel:

var qs = string.Format("q1={0}&q2={1}&q3={2}&q4={3}&q5={4}&q6={5}", 
    someVar, anotherVarWithLongName, var3, var4, var5, var6)

in der können wie folgt geschrieben werden und es ist einfacher zu Lesen:

var qs=$"q1={someVar}&q2={anotherVarWithLongName}&q3={var3}&q4={var4}&q5={var5}&q6={var6}";

Ab C# 6.0 interpolierte strings kann verwendet werden, um dies zu tun, vereinfacht, die das format sogar noch mehr.

var name = "Bill";
var surname = "Gates";
MessageBox.Show($"Welcome to the show, {name} {surname}!");

Mit einer interpolierten Zeichenfolgenausdruck, der aussieht wie ein template-string enthält Ausdrücke.Eine interpolierte Zeichenfolge erstellt eine Zeichenfolge durch den Austausch der enthaltenen Ausdrücke mit dem ToString Zusicherungen der Ausdrücke " Ergebnis.

Interpolierte strings haben eine ähnliche Leistung, String.Format, sondern verbessert die Lesbarkeit und die kürzere syntax, aufgrund der Tatsache, dass die Werte und Ausdrücke, die eingefügt werden, in-line.

Lesen Sie auch dieser Artikel dotnetperls auf die string-interpolation.

Wenn Sie sich für einen Standard-Weg zur Formatierung des strings, das macht Sinn in Bezug auf Lesbarkeit und Leistung (außer wenn Mikrosekunden wird einen Unterschied machen in Ihrem spezifischen Anwendungsfall).

  1. Formatierung ist dem “.NET" Weg, es zu tun.Bestimmte refactoring-tools (Refactor!für eine) werden auch vorschlagen, die zu überarbeiten die concat-Stil code für die Verwendung der Formatierung.
  2. Formatieren ist einfacher, um eine Optimierung für die compiler (obwohl der zweite wird wohl umgestaltet werden, um die Verwendung der 'Concat' Methode, die ist schnell).
  3. Die Formatierung ist in der Regel klarer zu Lesen (vor allem mit "fancy" - Formatierung).
  4. Formatierung bedeutet implizite Gespräche an.ToString " auf alle Variablen, die ist gut für die Lesbarkeit.
  5. Nach der "effective C#", das .NET 'WriteLine' und 'Format' - Implementierungen sind Durcheinander, Sie autobox alle Werttypen (was schlecht ist)."Effective C#", rät durchführen '.ToString " fordert explizit, was IMHO ist falsch (siehe Jeff posten)
  6. In dem moment, Formatierung, geben Sie keine Hinweise überprüft der compiler, was zu Laufzeitfehlern.Dies könnte sich jedoch geändert werden in Zukunft Versionen.

Ich würde verwenden Sie die String.Format, aber ich hätte auch den format-string in der Ressource-Dateien, so dass es kann lokalisiert sein, für andere Sprachen.Mit einem einfachen string-concat nicht erlauben, das zu tun.Natürlich, wenn Sie nicht jemals brauchen, um zu lokalisieren, dass die string ist dies nicht ein Grund zum nachdenken.Es hängt wirklich davon ab, was der string ist für.

Wenn es geht, zeigte der Benutzer verwende ich String.Format, so kann ich lokalisieren, wenn ich muss - und FxCop wird die Rechtschreibprüfung überprüfen es für mich, nur für den Fall :)

Wenn es zahlen enthält oder sonstige nicht-string-Dinge (z.B.Termine), würde ich die Verwendung von String.Format, weil es mir mehr Kontrolle über die Formatierung.

Wenn es für den Aufbau einer Abfrage wie SQL, die ich verwenden würde Linq.

Wenn für die Verkettung von strings innerhalb einer Schleife, würde ich verwenden StringBuilder zur Vermeidung von Leistungsproblemen.

Wenn es für eine Ausgabe der Nutzer nicht sehen, und wird nicht Wirkung die Leistung, die ich verwenden würde, String.Format denn ich bin in der Gewohnheit der Verwendung es trotzdem und ich bin nur daran gewöhnt :)

Wenn man sich mit etwas, das leicht zu Lesen (und das ist der größte Teil des Codes), würd ich mich mit dem operator überladen version, es sei denn:

  • Der code muss ausgeführt werden millionenfach
  • Tun Sie Tonnen von concats (mehr als 4 ist ein ton)
  • Der Kodex richtet sich an die Compact Framework

Unter zumindest zwei von diesen Umständen, ich würde verwenden Sie StringBuilder statt.

Ich wählen, basierend auf Lesbarkeit.Ich bevorzuge die format option, wenn es etwas text, um die Variablen.In diesem Beispiel:

Console.WriteLine("User {0} accessed {1} on {2}.", 
                   user.Name, fileName, timestamp);

Sie verstehen die Bedeutung auch ohne Variablennamen, in der Erwägung, dass die concat-Funktion ist überladen mit Zitaten und + Zeichen und verwirrt meine Augen:

Console.WriteLine("User " + user.Name + " accessed " + fileName + 
                  " on " + timestamp + ".");

(Ich habe mir Mikes Beispiel, weil ich es mag)

Wenn der format-string bedeutet nicht viel ohne den Variablen-Namen, die ich habe zu verwenden concat:

   Console.WriteLine("{0} {1}", p.FirstName, p.LastName);

Die format-option macht mich das Lesen der Namen der Variablen und Ihre Zuordnung zu den entsprechenden Nummern.Der concat option erfordert nicht, dass.Ich bin immer noch verwirrt durch die Zitate und die + - Zeichen, aber die alternative ist schlimmer.Ruby?

   Console.WriteLine(p.FirstName + " " + p.LastName);

Performance-wise, ich erwarte, dass die format-option werden langsamer, dann die concat -, da-format erforderlich, die Kette zu analysiert.Ich kann mich nicht erinnern, dass zur Optimierung dieser Art von Unterricht, aber wenn ich es täte, würde ich schauen, string Methoden wie Concat() und Join().

Der andere Vorteil mit format ist, dass der format-string kann in einer Konfigurationsdatei.Sehr praktisch mit Fehlermeldungen und der text der Benutzeroberfläche.

Wenn Sie beabsichtigen, zu lokalisieren das Ergebnis, dann String.Format ist wichtig, weil verschiedene Natürliche Sprachen können nicht einmal die Daten in der gleichen Reihenfolge.

Ich denke, das hängt stark auf wie Komplex die Ausgabe.Ich Neige dazu, zu wählen, welches Szenario am besten funktioniert in der Zeit.

Wählen Sie die richtigen tool basiert auf der Arbeit :D Welcher sieht am saubersten!

Ich bevorzuge die zweite auch, aber ich habe keine rationalen Argumente, die in dieser Zeit zu unterstützen, dass position.

Nice one!

Gerade Hinzugefügt

        s.Start();
        for (var i = 0; i < n; i++)
            result = string.Concat(p.FirstName, " ", p.LastName);
        s.Stop();
        ceElapsedMilliseconds = s.ElapsedMilliseconds;
        ceElapsedTicks = s.ElapsedTicks;
        s.Reset();

Und es ist sogar schneller (ich denke, string.Concat genannt ist in beiden Beispielen, aber der erste, erfordert eine gewisse Art der übersetzung).

1000000 x result = string.Format("{0} {1}", p.FirstName, p.LastName); took: 249ms - 3571621 ticks
1000000 x result = (p.FirstName + " " + p.LastName); took: 65ms - 944948 ticks
1000000 x result = string.Concat(p.FirstName, " ", p.LastName); took: 54ms - 780524 ticks

Da ich nicht denke, dass die Antworten hier alles abzudecken, und ich möchte auch einen kleinen Zusatz hier.

Console.WriteLine(string format, params object[] pars) Aufrufe string.Format.Das '+' bedeutet die string-Verkettung.Ich glaube nicht, dass dies immer zu tun hat mit Stil;Ich Neige zu der Mischung der beiden Stile-je nach Kontext bin ich in.

Kurze Antwort

Die Entscheidung, die Sie sind mit zu tun hat mit dem string-Zuweisung.Ich werde versuchen, es einfach zu machen.

Sagen wir, du hast

string s = a + "foo" + b;

Wenn Sie diese ausführen, es wird ausgewertet wie folgt:

string tmp1 = a;
string tmp2 = "foo" 
string tmp3 = concat(tmp1, tmp2);
string tmp4 = b;
string s = concat(tmp3, tmp4);

tmp hier ist nicht wirklich eine lokale variable, aber es ist eine vorübergehende für die JIT - (es geschoben, die auf der IL-stack).Wenn Sie drücken, einen string auf dem stack (wie ldstr in IL für Literale), setzen Sie eine Referenz auf einen string-Zeiger auf den stack.

Der moment, den Sie nennen concat diese Referenz wird zu einem problem, da gibt es keine string-Referenz enthält Zeichenfolgen.Dies bedeutet, dass .NET reservieren muss ein neuer block im Speicher, und dann füllen Sie es mit der zwei strings.Der Grund dafür ist ein problem, weil die Zuteilung ist relativ teuer.

Welche änderungen die Frage:Wie können Sie reduzieren die Anzahl der concat Operationen?

So, die grobe Antwort ist: string.Format für >1 concats, '+' wird gut funktionieren für 1 concat.Und wenn Sie nicht zu tun, micro-performance-Optimierungen, string.Format wird nur gut funktionieren, in den Allgemeinen Fall.

Ein Hinweis über die Kultur

Und dann gibt es etwas namens Kultur...

string.Format ermöglicht Sie zu verwenden CultureInfo in Ihrer Formatierung.Ein einfaches operator '+' verwendet, die der aktuellen Kultur.

Dies ist vor allem ein wichtiger Hinweis, wenn Sie sind schreiben, Datei Formate, und f.ex. double Werte, die Sie "hinzufügen", um einen string.Auf verschiedenen Maschinen, könnten Sie am Ende mit verschiedenen Saiten, wenn Sie nicht verwenden string.Format mit einer expliziten CultureInfo.

F. ex.überlegen Sie, was passiert, wenn Sie ändern a '.' für einen ',' beim schreiben der CSV (comma-seperated-values-Datei...im niederländischen das Dezimaltrennzeichen ein Komma ist, so dass Ihre Benutzer möglicherweise nur eine "lustige" überraschung.

Detaillierte Antwort

Wenn Sie nicht wissen, die genaue Größe der string vorher, es ist am besten, um Hilfe von Richtlinien, wie diese zu overallocate die Puffer, die Sie verwenden.Der pufferbereich wird zuerst gefüllt, nach dem die Daten kopiert.

Wachsen bedeutet, dass die Zuweisung eines neuen Blocks des Gedächtnisses und kopieren der alten Daten auf das neue Puffer.Der alte block der Speicher kann anschließend freigegeben werden.Sie bekommen in der unteren Zeile an dieser Stelle:wachsen ist eine teure operation.

Der praktischste Weg, dies zu tun, ist die Verwendung eines overallocation Politik.Die meisten gemeinsame Politik zu overallocate Puffer in Potenzen von 2.Natürlich, Sie haben zu tun, wird es ein wenig klüger als das (da es keinen Sinn macht, zu wachsen 1,2,4,8, wenn Sie bereits wissen, müssen Sie 128 Zeichen), aber Sie erhalten das Bild.Die Politik sorgt Sie brauchen nicht zu viele der teuren Operationen, die ich oben beschrieben.

StringBuilder ist eine Klasse, die im Grunde overallocates die zugrunde liegenden Puffer in Potenzen von zwei. string.Format verwendet StringBuilder unter der Haube.

Das macht Ihre Entscheidung eine grundlegende trade-off zwischen overallocate-und-append(-multiple) (w/w.o.Kultur) oder einfach nur reservieren-und-Anhängen.

Persönlich, die zweite als alles, was Sie verwenden, ist im direkten Auftrag ausgegeben werden.In der Erwägung, dass mit die ersten, die Sie haben, übereinstimmen, den {0} und {1} mit dem richtigen var, die ist leicht zu vermasseln.

Zumindest ist es nicht so schlimm, wie der C++ - sprintf, wo wenn man den Variablentyp falsch, die ganze Sache wird die Luft zu sprengen.

Auch, weil die zweite ist, alle inline-und es nicht zu tun suchen und ersetzen für alle {0} Dinge, die letztere soll schneller sein...obwohl ich nicht sicher wissen.

Eigentlich mag ich die erste, weil, wenn es eine Menge von Variablen, vermischt mit dem text es scheint einfacher zu Lesen für mich.Plus, es ist einfacher zu deal mit den Anführungszeichen bei der Verwendung der string.Format (),, ähm, format.Hier ist anständige Analyse der string-Verkettung.

Ich habe immer gegangen, der string.Format () - route.Werden in der Lage zu speichern in Variablen Formaten wie Nathan ' s Beispiel ist ein großer Vorteil.In einigen Fällen kann ich anfügen einer Variablen, aber sobald mehr als 1 variable ist verkettet, die ich umgestalten zu verwenden, formatieren.

Oh, und nur der Vollständigkeit halber, die folgenden ist ein wenig schneller tickt als die normale Verkettung:

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));

Die erste (format) sieht besser aus auf mir.Es ist besser lesbar und Sie sind nicht die zusätzliche temporäre string-Objekte.

Ich war neugierig, wo StringBuilder Stand mit diesen tests.Ergebnisse unter...

class Program {
   static void Main(string[] args) {

      var p = new { FirstName = "Bill", LastName = "Gates" };

      var tests = new[] {
         new { Name = "Concat", Action = new Action(delegate() { string x = p.FirstName + " " + p.LastName; }) },
         new { Name = "Format", Action = new Action(delegate() { string x = string.Format("{0} {1}", p.FirstName, p.LastName); }) },
         new { Name = "StringBuilder", Action = new Action(delegate() {
            StringBuilder sb = new StringBuilder();
            sb.Append(p.FirstName);
            sb.Append(" ");
            sb.Append(p.LastName);
            string x = sb.ToString();
         }) }
      };

      var Watch = new Stopwatch();
      foreach (var t in tests) {
         for (int i = 0; i < 5; i++) {
            Watch.Reset();
            long Elapsed = ElapsedTicks(t.Action, Watch, 10000);
            Console.WriteLine(string.Format("{0}: {1} ticks", t.Name, Elapsed.ToString()));
         }
      }
   }

   public static long ElapsedTicks(Action ActionDelg, Stopwatch Watch, int Iterations) {
      Watch.Start();
      for (int i = 0; i < Iterations; i++) {
         ActionDelg();
      }
      Watch.Stop();
      return Watch.ElapsedTicks / Iterations;
   }
}

Ergebnisse:

Concat: 406 ticks
Concat: 356 ticks
Concat: 411 ticks
Concat: 299 ticks
Concat: 266 ticks
Format: 5269 ticks
Format: 954 ticks
Format: 1004 ticks
Format: 984 ticks
Format: 974 ticks
StringBuilder: 629 ticks
StringBuilder: 484 ticks
StringBuilder: 482 ticks
StringBuilder: 508 ticks
StringBuilder: 504 ticks

Nach der MCSD prep material, empfiehlt Microsoft die Verwendung der + - operator beim Umgang mit einer sehr kleinen Anzahl von Verkettungen (wahrscheinlich 2 bis 4).Ich bin mir immer noch nicht sicher, warum, aber es ist etwas zu prüfen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top