Czy powinienem używać .ToString () podczas łączenia zmiennych łańcuchowych i liczb całkowitych w C #?


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

Czy powinienem użyć:

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

lub

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

Czy zaleca się stosowanie ToString()podczas łączenia stringi int?


6
W a + "" + b + ""lub "" + a + b + "", to nie ma znaczenia: wszystko łączy ciąg. Ma a + b + ""to znaczenie: ai bsą dodawane jako pierwsze.
Tim S.

4
Uwaga dodatkowa: W VB.NET tej dwuznaczności można uniknąć, mając jawnego operatora konkatenacji ciągów : "Expression: " + awyrzuci błąd czasu kompilacji (przy włączonej opcji Strict On), "Expression: " & aprzeprowadzi konkatenację ciągu.
Heinzi

Pierwszy kod spowoduje boks (int do Int32), drugi nie. Drugi jest oczywiście szybszy.
Losowe alfabety

Odpowiedzi:


33

ToString stosowanie

Nie, nie powinieneś używać ToStringtutaj.

Łączenie ciągów automatycznie przekształca nie-ciągi w ciągi, co oznacza, że ​​twoje dwa warianty są prawie¹ identyczne:

Gdy jeden lub oba operandy mają ciąg znaków, predefiniowane operatory dodawania łączą reprezentację ciągu operandów.

Źródło: C # Specyfikacja języka: Operator dodawania, MSDN .

Z drugiej strony, pierwszy (bez ToString):

  • Jest krótszy do napisania,
  • Jest krótszy do przeczytania,
  • Jest łatwiejszy w utrzymaniu i:
  • pokazuje dokładnie intencję autora: konkatenację ciągów.

Więc wolę pierwszy.

Pod maską

Interesujące jest również to, co dzieje się pod maską. Jednym ze sposobów, aby to zobaczyć, jest obejrzenie kodu IL w LINQPad. Ten program:

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

jest przetłumaczony na następującą IL:

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

Widzisz to System.String.Concat? Oznacza to, że oryginalny kod można również zapisać w ten sposób, co przekłada się na dokładnie taką samą IL:

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

Po przeczytaniu dokumentacjistring.Concat(object[]) możesz dowiedzieć się, że:

Metoda łączy każdy obiekt w argumenty , wywołując ToStringmetodę bez parametrów tego obiektu; nie dodaje żadnych ograniczników.

Oznacza to, że ToStringjest zbędny. Również:

String.Empty jest używany zamiast dowolnego pustego obiektu w tablicy.

Który ładnie radzi sobie w przypadku, gdy niektóre operandy mają wartość zerową (patrz przypis 1).

Podczas gdy w ostatnim przykładzie konkatenacja została przetłumaczona string.Concat, należy również podkreślić optymalizacje kompilatora:

var a = "Hello " + "World";

jest przetłumaczony na:

ldstr       "Hello World"
stloc.0

Z drugiej strony:

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

jest przetłumaczony na:

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

Inne alternatywy

Istnieją oczywiście inne sposoby łączenia reprezentacji łańcuchowej obiektów w języku C #.

  1. StringBuilderjest używany, gdy trzeba wykonać wiele operacji konkatenacji i pomaga zmniejszyć liczbę utworzonych łańcuchów pośrednich. Decyzja, czy powinieneś użyć StringBuilderzwykłego konkatenacji, może nie być łatwa. Użyj profilera lub wyszukaj odpowiednie odpowiedzi na temat przepełnienia stosu.

    Korzystanie StringBuilderma poważną wadę polegającą na tym, że kod jest trudny do odczytania i utrzymania. W prostych przypadkach, jak ten w pytaniu, StringBuilderjest nie tylko szkodliwy dla czytelności kodu, ale także bezużyteczny pod względem wydajności.

  2. string.Join należy stosować, gdy trzeba dodać ograniczniki.

    Oczywiście, nigdy nie używaj string.Joinz pustym separatorem do łączenia łańcuchów.

  3. string.Formatmoże być stosowany, gdy szablony łańcuchów są preferowane zamiast konkatenacji łańcuchów. Jednym z przypadków, w których możesz preferować, jest to, że wiadomość może być zlokalizowana, jak sugeruje odpowiedź Kunthet.

    Korzystanie string.Formatma kilka wad, co sprawia, że ​​nie nadaje się do prostych przypadków, takich jak Twoja:

    • W przypadku prostych symboli zastępczych „{0}” często nie jest jasne, który parametr zmierza dokąd. Często pomyłkowo odwraca się parametry lub zapomina się o jednym. Na szczęście C # 6 wreszcie wprowadza interpolację łańcuchów, co rozwiązuje ten problem.

    • Wydajność środowiska wykonawczego może się obniżyć. Oczywiście nie zakładaj, że zawszestring.Format jest wolniejszy. Jeśli wydajność ma znaczenie, zmierz dwa podejścia i określ, które z nich jest szybsze, na podstawie rzeczywistych wyników zamiast założeń.

    • Kod jest nieco dłuższy do napisania, dłuższy do odczytu i trudniejszy w utrzymaniu, chociaż jest to bardzo niewielkie i nie powinno cię zbytnio niepokoić.


¹ Różnica pojawia się, gdy jest jeden z obiektów null. Bez ToString, A nullzostał zastąpiony przez pusty ciąg. Z ToString, A NullReferenceExceptionjest wyrzucane.


1
Z tego właśnie powodu (nieprzewidywalne zachowanie) łączenie łańcuchów z ciągiem +uważane jest za złą praktykę w większości języków. W tym przypadku skorzystałbym string.Concat, w wielu przypadkach string.Formatjest lepszy. Z pewnością nie jest w Pythonie +, a ponieważ PEP 3101 %jest również odradzany na korzyść str.format.
Arda Xi

2
Czy podstawienie pustego łańcucha jest nulltak naprawdę „ładnym sposobem”? Cóż, nie jest tak źle, jak „przy wznowieniu błędu dalej” ...
Deduplicator

Pod maską, jeśli konkatenujesz bez wywoływania .ToString (), boks nastąpi ... i Concat(object[])zostanie użyty zamiast Concat(string[]). Więc "string " + itak naprawdę nie jest identyczny z"string " + i.ToString()
Random Alphabets

@RandomAlphabets: ważny punkt. Różnica polega jednak na lokalizacji ToString(): kodu OP w jednym przypadku, System.String.Concatimplementacji w drugim przypadku. Tak więc odpowiedź pozostaje aktualna: nie pisz kodu, który nie przynosi korzyści.
Arseni Mourzenko

15

Zamiast tego należy użyć formatyzatora ciągów. Łatwiej jest sformatować swój numer na reprezentację ciągu lub lokalizację. na przykład:

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

Więcej informacji na MSDN .

Jednak formatator łańcuchów jest mniej czytelny (a może także wydajność) niż konkatenacja łańcucha.


6
Chcesz wyjaśnić, dlaczego ta opcja jest lepsza?
Inżynier świata

@WorldEngineer: Zaktualizowałem wyjaśnienie.
kunthet

12
Nie znam wszystkich, ale uważam to za bardziej czytelne. Może dlatego, że dorastałem z C, gdzie s [n] printf jest jedyną realistyczną opcją dla tego rodzaju kodu.
Jules

2
Ale w ten sposób podaje się trzy źródła błędów zamiast jednego. Kiedy dodajesz coś do łańcucha, 1) musisz zmienić format łańcucha, 2) nie zapomnij dodać nowego parametru na liście, 3) spróbuj wybrać właściwe miejsce na liście, na którym powinien zostać umieszczony nowy parametr.
Ruslan

2
Po prostu włącz się i daj znać o nadchodzącej funkcji interpolacji łańcuchów w C # 6. Napisz „Wyrażenie: \ {a} + \ {b} = \ {sum}”, aby uzyskać ten sam wynik. codeproject.com/Articles/846566/…
cwap

-2

Jeśli używasz +konkatenacji, sama używa String.Concatmetody. Sam łańcuch nie ujawnia operatora +.

na przykład:

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

jest skompilowany w:

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

Jeśli zadzwonisz bezpośrednio ToString, unikniesz boksowania i wywołania Concat(string, string)przeciążenia. Dlatego ToStringpołączenie będzie nieco bardziej wydajne, ale niewystarczające. Lepiej skorzystaj z przykładu, który Twoim zdaniem jest bardziej czytelny.


2
zdaje się to jedynie powtarzać punkty poczynione i wyjaśnione w poprzedniej odpowiedzi : „Łączenie ciągów automatycznie przekształca nie-ciągi w ciągi ...”
komentuje
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.