Sollte ich .ToString () verwenden, wenn ich String- und Integer-Variablen in C # verkette?

19
int a = 1;
int b = 2;
int sum = a + b;
string expression = "Expression: " + a + " + " + b + " = " + sum;
Console.WriteLine(expression); //displays Expression 1 + 2 = 3

Sollte ich es benutzen:

string expression = "Expression: " + a + " + " + b + " = " + sum;

oder

string expression = "Expression: " + a.ToString() + " + " + b.ToString() + " = " + result.ToString();

Wird empfohlen, ToString()beim Verketten stringund zu verwenden int?

Akainu
quelle
6
In a + "" + b + ""oder "" + a + b + ""spielt es keine Rolle: Es ist alles eine Verkettung von Zeichenfolgen. Darin spielt a + b + ""es eine Rolle: aund bwerden zuerst hinzugefügt.
Tim S.
4
Randnotiz: In VB.NET wird diese Mehrdeutigkeit vermieden, indem ein expliziter Operator für die Verkettung von Zeichenfolgen angegeben wird : Es "Expression: " + awird ein Fehler bei der Kompilierung ausgegeben (mit Option Strict On), und es "Expression: " & awird eine Verkettung von Zeichenfolgen durchgeführt.
Heinzi
Der erste Code führt zum Boxen (int bis Int32), der zweite nicht. Der zweite ist offensichtlich schneller.
Zufällige Alphabete

Antworten:

33

ToString Verwendung

Nein, du solltest nicht verwenden ToString .

Durch die Verkettung von Zeichenfolgen werden Nicht-Zeichenfolgen automatisch in Zeichenfolgen umgewandelt. Dies bedeutet, dass Ihre beiden Varianten nahezu identisch sind:

Wenn einer oder beide Operanden vom Typ Zeichenfolge sind, verketten die vordefinierten Additionsoperatoren die Zeichenfolgendarstellung der Operanden.

Quelle: C # Sprachspezifikation: Additionsoperator, MSDN .

Auf der anderen Seite die erste (ohne ToString ):

  • Ist kürzer zu schreiben,
  • Ist kürzer zu lesen,
  • Ist einfacher zu warten und:
  • zeigt genau die Absicht des Autors: Strings zu verketten.

Also lieber den ersten.

Unter der Haube

Interessant ist auch, was unter der Haube passiert. Eine Möglichkeit, dies zu sehen, ist das Betrachten des IL-Codes in LINQPad. Dieses Programm:

void Main()
{
    var a = 3;
    var b = " Hello";
    var c = a + b;
    Console.WriteLine(c);
}

wird in folgende IL übersetzt:

IL_0001:  ldc.i4.3    
IL_0002:  stloc.0     // a
IL_0003:  ldstr       " Hello"
IL_0008:  stloc.1     // b
IL_0009:  ldloc.0     // a
IL_000A:  box         System.Int32
IL_000F:  ldloc.1     // b
IL_0010:  call        System.String.Concat
IL_0015:  stloc.2     // c
IL_0016:  ldloc.2     // c
IL_0017:  call        System.Console.WriteLine

Siehst System.String.Concatdu das ? Das bedeutet, dass der Originalcode auch so geschrieben werden kann, was genau dasselbe IL bedeutet:

void Main()
{
    var a = 3;
    var b = " Hello";
    var c = string.Concat(a, b); // This is the line which was changed.
    Console.WriteLine(c);
}

Wenn Sie die Dokumentation vonstring.Concat(object[]) lesen , stellen Sie möglicherweise Folgendes fest:

Die Methode verkettet jedes Objekt in Argumenten, indem sie die parameterlose ToStringMethode dieses Objekts aufruft . Es werden keine Begrenzer hinzugefügt.

Das heißt, das ToStringist überflüssig. Ebenfalls:

String.Empty wird anstelle eines Nullobjekts im Array verwendet.

Was gut mit dem Fall umgeht, in dem einige der Operanden null sind (siehe Fußnote 1).

Während im letzten Beispiel die Verkettung in übersetzt wurde string.Concat, sollte man auch Compiler-Optimierungen hervorheben:

var a = "Hello " + "World";

wird übersetzt in:

ldstr       "Hello World"
stloc.0

Auf der anderen Seite:

var a = string.Concat("Hello ", "World");

wird übersetzt in:

ldstr       "Hello "
ldstr       "World"
call        System.String.Concat
stloc.0

Andere Alternativen

Es gibt natürlich auch andere Möglichkeiten, Zeichenfolgendarstellungen von Objekten in C # zu verketten.

  1. StringBuilderwird verwendet, wenn Sie viele Verkettungsvorgänge ausführen müssen, und verringert die Anzahl der erstellten Zwischenzeichenfolgen. Die Entscheidung, ob Sie eine StringBuilderoder eine gewöhnliche Verkettung verwenden sollen, ist möglicherweise nicht einfach. Verwenden Sie einen Profiler oder suchen Sie nach relevanten Antworten für den Stapelüberlauf.

    Die Verwendung StringBuilderhat den großen Nachteil, dass der Code schwer zu lesen und zu warten ist. In einfachen Fällen wie dem in Ihrer Frage StringBuilderist dies nicht nur schädlich für die Lesbarkeit des Codes, sondern auch in Bezug auf die Leistung unbrauchbar.

  2. string.Join sollte verwendet werden, wenn Trennzeichen hinzugefügt werden müssen.

    Offensichtlich verwendet nie string.Joinmit einem leeren Begrenzer zu verketten Zeichenfolge.

  3. string.Formatkann verwendet werden, wenn String-Templating der String-Verkettung vorgezogen wird. Einer der Fälle, in denen Sie dies bevorzugen, ist der, in dem die Nachricht lokalisiert wird, wie in der Antwort von kunthet vorgeschlagen.

    Das Verwenden string.Formathat mehrere Nachteile, die es für einfache Fälle wie Ihren ungeeignet machen:

    • Bei einfachen "{0}" - Platzhaltern ist oft unklar, welcher Parameter wohin führt. Es kommt häufig vor, dass die Parameter versehentlich vertauscht oder vergessen werden. Glücklicherweise führt C # 6 endlich eine String-Interpolation ein, die dieses Problem löst.

    • Die Laufzeitleistung kann sich verschlechtern. Natürlich nicht davon ausgehen, string.Formatist immer langsamer. Wenn es auf die Leistung ankommt, messen Sie zwei Ansätze und bestimmen Sie anhand Ihrer tatsächlichen Ergebnisse, welche Ansätze schneller sind als Annahmen.

    • Der Code ist etwas länger zu schreiben, länger zu lesen und schwerer zu warten, obwohl dies äußerst geringfügig ist und Sie nicht allzu sehr stören sollte.


¹ Der Unterschied wird angezeigt, wenn eines der Objekte ist null. Ohne ToStringwird a nulldurch eine leere Zeichenfolge ersetzt. Mit ToStringwird ein NullReferenceExceptiongeworfen.

Arseni Mourzenko
quelle
1
Aus genau diesem Grund (unvorhersehbares Verhalten) wird die Verkettung von Zeichenfolgen mit dem +in den meisten Sprachen als schlechte Praxis angesehen. In diesem Fall würde ich string.Concatin vielen Fällen string.Formatbesser. Es ist sicherlich nicht Pythonic zu verwenden +, und da PEP 3101 %ist auch für entmutigt str.format.
Arda Xi
2
Ersetzt man eine leere Zeichenfolge, um nullwirklich "gut damit umzugehen"? Nun, es ist nicht so schlimm wie "On Error Resume Next" ...
Deduplicator
Unter der Haube, wenn Sie verketten, ohne .ToString () aufzurufen, passiert Boxen ... und Concat(object[])wird stattdessen verwendet Concat(string[]). Ist "string " + ialso eigentlich nicht identisch mit"string " + i.ToString()
Random Alphabets
@ RandomAlphabets: gültiger Punkt. Der Unterschied liegt jedoch einfach in der Position von ToString(): OPs Code in einem Fall, System.String.Concatder Implementierung in dem anderen Fall. Die Antwort bleibt also gültig: Schreiben Sie nicht den Code, der keinen Nutzen hat.
Arseni Mourzenko
15

Verwenden Sie stattdessen den Zeichenfolgenformatierer. Es ist einfacher, Ihre Nummer in Zeichenfolgendarstellung oder Lokalisierung zu formatieren. z.B:

string expression = string.Format("Expression: {0} + {1} = {2}", a, b, sum);

Weitere Informationen zu MSDN .

Der Formatierer von Zeichenfolgen ist jedoch weniger lesbar (und möglicherweise auch weniger leistungsfähig) als die Verkettung von Zeichenfolgen.

Kunthet
quelle
6
Möchten Sie erklären, warum diese Option besser ist?
Weltingenieur
@WorldEngineer: Ich habe die Erklärung aktualisiert.
Kunthet
12
Ich kenne nicht alle anderen, aber ich finde das eigentlich lesbarer. Vielleicht, weil ich mit C aufgewachsen bin, wo s [n] printf die einzig realistische Option für diese Art von Code ist.
Jules
2
Auf diese Weise ergeben sich jedoch drei Fehlerquellen anstelle einer. Wenn Sie der Zeichenfolge etwas hinzufügen, müssen Sie 1) die Formatzeichenfolge ändern, 2) nicht vergessen, neue Parameter in die Liste aufzunehmen, 3) versuchen, die richtige Stelle in der Liste auszuwählen, an der neue Parameter eingefügt werden sollen.
Ruslan
2
Wollen Sie sich nur einschalten und Sie über die bevorstehende String-Interpolationsfunktion in C # 6 informieren. Sie werden "Expression: \ {a} + \ {b} = \ {sum}" schreiben, um das gleiche Ergebnis zu erhalten. codeproject.com/Articles/846566/…
cwap
-2

Wenn Sie +Verkettung verwenden, wird selbst die String.ConcatMethode verwendet. String selbst macht keinen + -Operator verfügbar.

beispielsweise:

int i = 10;
string str = "hello" + i;

ist kompiliert in:

int i = 10;
object o1 = "hello";
object o2 = i; // Note boxing
string str = string.Concat(o1, o2);

Wenn Sie direkt anrufen ToString, wird das Boxen vermieden und die Concat(string, string)Überlastung aufgerufen . Daher wird der ToStringAnruf etwas effizienter sein, obwohl er nicht signifikant genug ist. Sie sollten sich an das Beispiel halten, das Ihrer Meinung nach besser lesbar ist.

sohaiby
quelle
2
dies scheint lediglich die in der vorherigen Antwort gemachten und erklärten Punkte zu wiederholen : "String-Verkettung wandelt automatisch Nicht-Strings in Strings um ..."
gnat