String output: format czy concat w C#?

Załóżmy, że chcesz wyprowadzać lub łączyć łańcuchy. Który z poniższych stylów preferujesz?

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

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

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

Czy wolisz używać formatu, czy po prostu Konkatedra? Jaki jest Twój ulubiony? Czy jeden z nich rani ci oczy?

Czy masz jakieś racjonalne argumenty, aby użyć jednego, a nie drugiego?

Wybrałbym drugą.
Author: Philippe, 2008-08-19

30 answers

Spróbuj tego kodu.

Jest to nieco zmodyfikowana wersja twojego kodu.
1. Usunąłem konsolę.WriteLine, ponieważ jest to prawdopodobnie kilka rzędów wielkości wolniejsze niż to, co próbuję zmierzyć.
2. Uruchamiam Stoper przed pętlą i Zatrzymuję go zaraz po tym, w ten sposób nie tracę precyzji, jeśli funkcja bierze np. 26.4 kleszczy do wykonania.
3. Sposób, w jaki podzieliłeś wynik przez niektóre iteracje, był błędny. Zobacz, co się stanie, jeśli masz 1000 milisekund i 100 milisekundy. W obu sytuacjach otrzymasz 0 ms po podzieleniu przez 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);

Oto moje wyniki:

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

 86
Author: Michał Piaskowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-01 06:15:41

Jestem zdumiony, że tak wiele osób od razu chce znaleźć kod, który wykonuje się najszybciej. Jeśli jeden milion iteracji zajmie mniej niż sekundę, czy będzie to w jakikolwiek sposób zauważalne dla użytkownika końcowego? Mało prawdopodobne.

Przedwczesna optymalizacja = porażka.

Wybrałbym opcję String.Format, tylko dlatego, że ma to największy sens z architektonicznego punktu widzenia. Nie obchodzi mnie wydajność, dopóki nie stanie się problemem (i jeśli to czy, zadałbym sobie pytanie: Czy muszę konkatenować milion nazwisk na raz? Na pewno nie wszystkie zmieszczą się na ekranie...)

Zastanów się, czy twój Klient później chce to zmienić, aby mógł skonfigurować, czy wyświetlać "Firstname Lastname" Czy {[2] } z opcją Format, jest to łatwe - po prostu zamień łańcuch formatu. Z concat, będziesz potrzebował dodatkowego kodu. Jasne, że to nie brzmi jak wielka sprawa w tym konkretnym przykładzie, ale ekstrapolować.

 153
Author: Fredrik Kalseth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-29 11:55:59

[[2]} O rany - po przeczytaniu jednej z innych odpowiedzi próbowałem odwrócić kolejność operacji - więc najpierw konkatenacja, potem ciąg znaków.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

Więc kolejność operacji robi ogromną różnicę, a raczej pierwsza operacja jest zawsze znacznie wolniejsza.

Oto wyniki biegu, w którym operacje są wykonywane więcej niż jeden raz. Próbowałem zmienić kolejność, ale ogólnie rzecz biorąc, wszystko przebiega zgodnie z tymi samymi zasadami, gdy pierwszy wynik jest ignorowane:

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

Jak widać kolejne uruchomienia tej samej metody (zrefakturowałem kod na 3 metody) są przyrostowo szybsze. Najszybsza wydaje się konsola.WriteLine (String.Konkat(...)) metoda, po której następuje zwykła konkatenacja, a następnie sformatowane operacje.

Początkowe opóźnienie w uruchomieniu jest prawdopodobnie inicjalizacją strumienia konsoli, jak umieszczenie konsoli.Writeline ("Start!"), zanim pierwsza operacja przywróciła wszystkie czasy do normy.

 54
Author: samjudson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-11 13:43:27

Ciągi znaków są niezmienne, co oznacza, że ten sam mały kawałek pamięci jest używany w kółko w Twoim kodzie. Dodawanie tych samych dwóch ciągów razem i tworzenie tego samego nowego ciągu w kółko nie wpływa na pamięć. . Net jest wystarczająco inteligentny, aby użyć tego samego odniesienia do pamięci. Dlatego Twój kod nie testuje różnicy między dwiema metodami concat.

Przymierz to dla rozmiaru:

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();

Przykładowe Wyjście:

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
 35
Author: MrPhil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-02 20:04:46

Szkoda biednych tłumaczy

Jeśli wiesz Twoja aplikacja pozostanie w języku angielskim, to dobrze, zachowaj Tiki zegara. Jednak wiele kultur zwykle widzi Lastname Firstname na przykład w adresach.

Więc użyj string.Format(), zwłaszcza jeśli masz zamiar kiedykolwiek aplikacja iść gdziekolwiek, że angielski nie jest pierwszym językiem.

 23
Author: Jeremy McGee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-30 21:11:53

Oto moje wyniki Ponad 100 000 iteracji:

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

A oto kod ławki:

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");

Więc Nie wiem, czyja odpowiedź do Marka jako odpowiedź:)

 14
Author: Philippe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-09 12:49:01

Łączenie łańcuchów jest w porządku w takim prostym scenariuszu - jest bardziej skomplikowane z czymś bardziej skomplikowanym niż to, nawet LastName, FirstName. Dzięki temu formatowi możesz na pierwszy rzut oka zobaczyć, jaka będzie ostateczna struktura ciągu znaków podczas czytania kodu, z konkatenacją staje się prawie niemożliwe natychmiastowe rozpoznanie ostatecznego wyniku(z wyjątkiem bardzo prostego przykładu, takiego jak ten).

Na dłuższą metę oznacza to, że kiedy wrócisz, by coś zmienić w formacie ciągów znaków możesz albo wejść i wprowadzić kilka poprawek do ciągu formatu, albo pomarsz czoło i zacznij poruszać się po wszystkich rodzajach akcesoriów do właściwości zmieszanych z tekstem, co jest bardziej prawdopodobne, że wprowadzi problemy.

Jeśli używasz. NET 3.5 możesz użyć metody rozszerzenia , takiej jak ta i uzyskać łatwy przepływ, poza składnią mankietu, TAK:

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

Wreszcie, jak aplikacja rośnie w złożoności możesz zdecydować, że sanely zachowaj ciągi znaków w aplikacji, którą chcesz przenieść do pliku zasobów w celu zlokalizowania lub po prostu do statycznego pomocnika. Będzie to znacznie łatwiejsze do osiągnięcia, jeśli konsekwentnie używasz formatów, a Twój kod może być po prostu refakturowany, aby użyć czegoś takiego jak

string name = String.Format(ApplicationStrings.General.InformalUserNameFormat,this.FirstName,this.LastName);
 9
Author: Nathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 15:56:23

Do bardzo prostej manipulacji użyłbym konkatenacji, ale po przekroczeniu 2 lub 3 elementów Format staje się bardziej odpowiedni IMO.

Kolejny powód, aby preferować String.Format polega na tym, że ciągi.NET są niezmienne i robi to w ten sposób tworzy mniej tymczasowych/pośrednich kopii.

 7
Author: user2189331,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 15:50:44

Podczas gdy całkowicie rozumiem preferencje stylu i wybrałem konkatenację dla mojej pierwszej odpowiedzi częściowo opartej na moich własnych preferencjach, część mojej decyzji opierała się na myśli, że konkatenacja będzie szybsza. Tak więc z ciekawości Przetestowałem go i wyniki były oszałamiające, szczególnie dla tak małego Sznurka.

Używając następującego kodu:

    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");

Otrzymałem następujące wyniki:

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

Używanie metody formatowania jest ponad 100 razy wolniejsze!! Konkatenacja nie nawet Zarejestruj się jako 1ms, dlatego wypisuję również Tiki timera.

 6
Author: Adam Haile,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 16:02:27

Do podstawowej konkatenacji ciągów zazwyczaj używam drugiego stylu-łatwiejszego do odczytania i prostszego. Jeśli jednak robię bardziej skomplikowaną kombinację ciągów, zazwyczaj wybieram ciąg.Format.

String.Format oszczędza na wielu cytatach i plusach...

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

Zapisano tylko kilka charicterów, ale myślę, że w tym przykładzie format czyni go znacznie czystszym.

 5
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 15:55:01

Lepszym testem byłoby oglądanie pamięci za pomocą Perfmon i liczników pamięci CLR. Rozumiem, że cały powód, dla którego chcesz użyć sznurka.Formatowanie zamiast tylko łączenia ciągów jest, ponieważ ciągi są niezmienne, niepotrzebnie obciążasz garbage collector tymczasowymi ciągami, które należy odzyskać w następnym przejściu.

StringBuilder i String.Format, choć potencjalnie wolniejszy, jest bardziej wydajny w pamięci.

Co w tym złego konkatenacja sznurków?

 5
Author: David Hill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 14:27:23

Generalnie wolę ten pierwszy, ponieważ szczególnie gdy ciągi się wydłużają, można go dużo łatwiej odczytać.

Inną korzyścią jest, jak sądzę, jedna z wydajności, ponieważ ta ostatnia faktycznie wykonuje 2 instrukcje tworzenia ciągu przed przekazaniem ostatniego ciągu do konsoli.Metoda zapisu. Sznurek.Format używa Stringbuildera pod okładkami, więc unika się wielu konkatenacji.

Należy jednak zauważyć, że jeśli parametry są przekazywane do String.Format (i inne takie metody jak konsola.Write) są typami wartości, a następnie będą one boksowane przed przekazaniem, co może zapewnić własne trafienia wydajności. post na blogu o tym tutaj .

 5
Author: samjudson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-01 11:31:12

Począwszy od C # 6.0 interpolowane łańcuchy mogą być używane do tego celu, co upraszcza format jeszcze bardziej.

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

Interpolowane wyrażenie łańcuchowe wygląda jak łańcuch szablonu zawierający wyrażenia. Interpolowane wyrażenie łańcuchowe tworzy łańcuch poprzez zastąpienie zawartych wyrażeń represjonacjami ToString wyników wyrażeń.

Interpolowane struny mają podobną wydajność do strun.Format, ale lepsza czytelność i krótsza składnia, ze względu na to, że wartości i wyrażenia są wstawiane w wierszu.

Proszę również zapoznać się z tym artykułem dotnetperls na temat interpolacji łańcuchów.

Jeśli szukasz domyślnego sposobu formatowania ciągów, ma to sens pod względem czytelności i wydajności (z wyjątkiem sytuacji, gdy mikrosekundy będą miały wpływ na konkretny przypadek użycia).

 5
Author: Saragis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-26 18:07:13
  1. formatowanie jest sposobem". NET". Niektóre narzędzia do refaktoryzacji (Refactor! dla jednego) zaproponuje nawet refaktorowanie kodu w stylu concat, aby użyć stylu formatowania.
  2. formatowanie jest łatwiejsze do optymalizacji dla kompilatora(chociaż drugi prawdopodobnie zostanie zrefakturowany, aby użyć metody 'Concat', która jest szybka).
  3. formatowanie jest zwykle bardziej czytelne (szczególnie w przypadku formatowania "fantazyjnego").
  4. formatowanie oznacza niejawne wywołania do ".ToString " na wszystkich zmiennych, co jest dobre dla czytelności.
  5. zgodnie z " efektywnym C#", implementacje. NET 'WriteLine' i 'Format' są popsute, autoboxują wszystkie typy wartości (co jest złe). "Effective C# "radzi wykonać".ToString 'rozmowy jawnie, co IMHO jest fałszywe (patrz Jeff' s posting )
  6. w tej chwili podpowiedzi typu formatowania nie są sprawdzane przez kompilator, co powoduje błędy uruchomieniowe. Można to jednak zmienić w przyszłych wersjach.
 4
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 15:59:21

Wybieram na podstawie czytelności. Wolę opcję format, gdy wokół zmiennych jest trochę tekstu. W tym przykładzie:

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

Rozumiesz znaczenie nawet bez nazw zmiennych, podczas gdy konkat jest zaśmiecony cudzysłowami i znakami + i myli mi oczy:

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

(pożyczyłem przykład Mike ' a, bo mi się podoba)

Jeśli łańcuch formatowania nie znaczy wiele bez nazw zmiennych, muszę użyć concat:

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

Opcja format sprawia, że czytam nazwy zmiennych i mapowanie ich do odpowiednich liczb. Opcja concat tego nie wymaga. Nadal jestem zdezorientowany cytatami i znakami+, ale alternatywa jest gorsza. Ruby?

   Console.WriteLine(p.FirstName + " " + p.LastName);
Jeśli chodzi o wydajność, spodziewam się, że opcja format będzie wolniejsza niż concat, ponieważ format wymaga przetworzenia ciągu . Nie pamiętam, żebym musiał optymalizować tego rodzaju instrukcje, ale gdybym to zrobił, przyjrzałbym się string metodom takim jak Concat() i Join().

Druga zaleta z formatem czy łańcuch formatowania może być umieszczony w pliku konfiguracyjnym. Bardzo przydatny z komunikatami o błędach i tekstem interfejsu użytkownika.

 4
Author: DonkeyMaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-13 08:35:59

Jeśli chcesz zlokalizować wynik, to String.Format jest niezbędny, ponieważ różne języki naturalne mogą nawet nie mieć danych w tej samej kolejności.

 4
Author: Christian Hayter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-07 14:50:08

Użyłbym Sznurka.Format, ale chciałbym również mieć ciąg formatowania w plikach zasobów, aby mógł być zlokalizowany dla innych języków. Użycie prostego ciągu concat nie pozwala na to. Oczywiście, jeśli nigdy nie będziesz musiał zlokalizować tego ciągu, nie jest to powód do myślenia. To naprawdę zależy od tego, do czego służy sznurek.

Jeśli ma być pokazany użytkownikowi, użyłbym String.Formatować, więc mogę zlokalizować, jeśli trzeba - i FxCop sprawdzi to za mnie, tylko w Etui:)

Jeśli zawiera liczby lub inne nie-ciągowe rzeczy( np. daty), użyłbym String.Format, ponieważ daje mi więcej kontroli nad formatowaniem .

Jeśli jest to do budowania zapytania takiego jak SQL, użyłbym Linq .

Jeśli do łączenia łańcuchów wewnątrz pętli, użyłbym StringBuilder , Aby uniknąć problemów z wydajnością.

Jeśli jest to dla jakiegoś wyjścia, które użytkownik nie zobaczy i nie będzie miało wpływu na wydajność, użyłbym String.Format bo jestem w przyzwyczajenie i tak go używam i jestem do tego przyzwyczajony:)

 4
Author: Wilka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-07 19:27:14

Za tydzień, 19 sierpnia 2015, to pytanie będzie miało dokładnie siedem (7) lat. Teraz jest lepszy sposób na zrobienie tego. lepsze pod względem konserwacji, ponieważ nie zrobiłem żadnego testu wydajności w porównaniu do tylko łączenia strun (ale czy to ma znaczenie w dzisiejszych czasach? kilka milisekund różnicy?). Nowy sposób robienia tego z C# 6.0:

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

Ta nowa funkcja jest lepsza , IMO i faktycznie lepsza w naszym przypadku ponieważ mamy kody gdzie buduj zapytania, których wartości zależą od pewnych czynników. Wyobraź sobie jedno zapytanie, w którym mamy 6 argumentów. Więc zamiast robić, na przykład:

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

In Można pisać w ten sposób i jest łatwiej czytać:

var qs=$"q1={someVar}&q2={anotherVarWithLongName}&q3={var3}&q4={var4}&q5={var5}&q6={var6}";
 4
Author: von v.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-12 03:18:07

Jeśli masz do czynienia z czymś, co musi być łatwe do odczytania (a to jest większość kodu), to zostałbym przy wersji przeciążenia operatora, chyba że:

  • kod musi być wykonany miliony razy
  • robisz Tony konkatów (więcej niż 4 to tonę)
  • kod jest skierowany do zwartego frameworka

W co najmniej dwóch takich okolicznościach użyłbym zamiast tego Stringbuildera.

 3
Author: plinth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 14:43:54

Myślę, że to zależy w dużej mierze od tego, jak skomplikowane jest wyjście. Zazwyczaj wybieram scenariusz, który najlepiej sprawdza się w danym czasie.

Wybierz odpowiednie narzędzie w zależności od zadania :D cokolwiek wygląda najczystiej!

 2
Author: mercutio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 15:50:34

Ja też wolę drugie, ale w tej chwili nie mam racjonalnych argumentów na poparcie tego stanowiska.

 2
Author: Chuck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 15:51:26

Nieźle!

Just added

        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();

I jest jeszcze szybszy (chyba string.Concat jest wywoływany w obu przykładach, ale pierwszy wymaga pewnego rodzaju tłumaczenia).

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
 2
Author: Philippe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-20 18:07:42

Ponieważ nie sądzę, aby odpowiedzi tutaj obejmują wszystko, chciałbym dodać mały dodatek tutaj.

Console.WriteLine(string format, params object[] pars) wywołania string.Format. '+'Oznacza konkatenację ciągu znaków. Nie sądzę, że zawsze ma to związek ze stylem; mam tendencję do mieszania tych dwóch stylów w zależności od kontekstu, w którym się znajduję.

Krótka odpowiedź

Decyzja, przed którą stoisz, ma związek z alokacją łańcuchów. Postaram się to uprościć.

Powiedz, że masz

string s = a + "foo" + b;

Jeśli to wykonasz, to Oceń w następujący sposób:

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

tmp tutaj nie jest tak naprawdę zmienna lokalna, ale jest tymczasowa dla JIT(jest wciśnięta na stos IL). Jeśli naciśniesz łańcuch znaków na stosie (np. ldstr w IL dla literałów), umieścisz na stosie odniesienie do wskaźnika łańcuchowego.

Moment wywołania concat to odniesienie staje się problemem, ponieważ nie ma żadnego odniesienia do łańcucha znaków, który zawiera oba łańcuchy. Oznacza to, że. NET musi przydzielić nowy blok pamięci, a następnie wypełnij go dwoma strunami. Powodem tego jest problem, ponieważ alokacja jest stosunkowo kosztowna.

Które zmienia pytanie na: jak zmniejszyć liczbę operacji concat?

Więc, szorstka odpowiedź brzmi: string.Format dla >1 konkat, ' + ' będzie działać dobrze dla 1 konkat. A jeśli nie zależy ci na optymalizacji mikro-wydajności, string.Format będzie działać dobrze w ogólnym przypadku.

Notka o kulturze

And then there ' s coś, co nazywa się kulturą...

string.Format umożliwia użycie CultureInfo w formatowaniu. Prosty operator " + " wykorzystuje aktualną kulturę.

Jest to szczególnie ważna uwaga, jeśli piszesz formaty plików i np. double wartości, które "dodajesz" do ciągu znaków. Na różnych maszynach możesz skończyć z różnymi ciągami znaków, jeśli nie użyjesz string.Format z jawnym CultureInfo.

F. ex. zastanów się, co się stanie, jeśli zmienisz a'.'na', ' pisząc swoje Plik z oddzielonymi przecinkami wartościami... w języku niderlandzkim separator dziesiętny jest przecinkiem, więc twój użytkownik może po prostu dostać "zabawną" niespodziankę.

Więcej detailed odpowiedź

Jeśli wcześniej nie znasz dokładnego rozmiaru łańcucha, najlepiej użyć takiej zasady, aby nadalokować bufory, których używasz. Przestrzeń Slacka jest najpierw wypełniana, po czym dane są kopiowane.

Wzrost oznacza przydzielenie nowego bloku pamięci i skopiowanie starych danych do nowego bufora. Stare blok pamięci może zostać zwolniony. W tym momencie otrzymujesz podsumowanie: uprawa jest kosztowną operacją.

Najbardziej praktycznym sposobem, aby to zrobić, jest zastosowanie polityki overallocation. Najczęstszą Polityką jest nadmierna alokacja buforów w potęgach 2. Oczywiście musisz zrobić to trochę mądrzej (ponieważ nie ma sensu rosnąć z 1,2,4,8, jeśli już wiesz, że potrzebujesz 128 znaków), ale masz obraz. Polisa zapewnia, że nie potrzebujesz zbyt wielu kosztownych operacji I opisane powyżej.

StringBuilder jest klasą, która zasadniczo overlocuje bufor bazowy w potęgach dwóch. string.Format używa StringBuilder pod maską.

To sprawia, że twoja decyzja jest podstawowym kompromisem pomiędzy nadalokacją i dołączeniem(-multiple) (w/w.O. culture) lub po prostu allocate-and-append.

 2
Author: atlaste,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-22 09:19:03

Osobiście, drugi, ponieważ wszystko, czego używasz, jest w bezpośredniej kolejności, w której zostanie wyświetlony. Natomiast przy pierwszym musisz dopasować {0} i {1} z odpowiednim var, który jest łatwy do bałaganu.

Przynajmniej nie jest tak źle jak w C++ sprintf gdzie jeśli źle ustawisz typ zmiennej to wszystko wybuchnie.

Również, ponieważ drugi jest cały inline i nie musi wykonywać żadnego wyszukiwania i zastępowania dla wszystkich {0} rzeczy, to drugie powinno być szybciej... chociaż Nie wiem na pewno.

 1
Author: Adam Haile,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 15:49:57

Podoba mi się ta pierwsza, ponieważ gdy jest dużo zmiennych mieszających się z tekstem, wydaje mi się łatwiejsza do odczytania. Ponadto łatwiej jest radzić sobie z cudzysłowami podczas korzystania z ciągu znaków.Format (), format. Oto porządna analiza konkatenacji łańcuchów.

 1
Author: adparadox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 15:57:20

I ' ve always gone the string.Format() Możliwość przechowywania formatów w zmiennych, takich jak Przykład Nathana, jest wielką zaletą. W niektórych przypadkach mogę dołączyć zmienną, ale raz więcej niż 1 zmienna jest konkatenowany i refactor użyć formatowania.

 1
Author: Scott Muc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-19 19:16:49

Oh, I tak dla kompletności, poniżej jest kilka kleszczy szybciej niż normalna konkatenacja:

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));
 1
Author: samjudson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-20 08:38:11

Pierwszy (format) wygląda mi lepiej. Jest bardziej czytelny i nie tworzysz dodatkowych tymczasowych obiektów string.

 1
Author: Rismo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-23 19:55:24

Byłem ciekaw, gdzie StringBuilder stoi z tymi testami. Wyniki poniżej...

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;
   }
}

Wyniki:

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
 1
Author: spoulson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 15:07:50

Zgodnie z materiałem przygotowawczym MCSD, Microsoft sugeruje użycie operatora + w przypadku bardzo małej liczby konkatenacji (prawdopodobnie od 2 do 4). Nadal Nie wiem dlaczego, ale trzeba to rozważyć.

 1
Author: Babak Naffas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-04 20:31:04