Wyjście String: Format lub concat w C #?

głosy
166

Załóżmy, że chcesz wyjść lub Concat strun. Które z poniższych stylów wolisz?

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

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

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

Czy raczej używać formatu czy też po prostu concat struny? Jaki jest Twój ulubiony? Jest jednym z tych cierpiących twoich oczach?

Czy masz jakieś racjonalne argumenty do korzystania z jednego, a nie inne?

Chciałbym przejść do drugiego.

Utwórz 19/08/2008 o 16:46
źródło użytkownik
W innych językach...                            


31 odpowiedzi

głosy
152

Jestem zdumiony, że tak wiele osób natychmiast znaleźć kod, który wykonuje się najszybciej. Jeśli jeden milion iteracje jeszcze trochę mniej niż sekundę, aby przetworzyć, jest to będzie w żaden sposób zauważalny dla użytkownika końcowego? Niezbyt prawdopodobne.

Przedwczesna optymalizacja = FAIL.

Pójdę z String.Formatopcją, tylko dlatego, że największy sens z punktu widzenia architektonicznego. Nie dbam o wydajności aż staje się problem (a jeśli tak, to zadaję sobie pytanie:? Czy muszę złączyć milion imion na raz całą pewnością nie będą one zmieścić na ekranie ...)

Rozważyć, czy później klient chce zmienić go tak, aby można je skonfigurować, czy wyświetlać "Firstname Lastname"lub "Lastname, Firstname."z opcją formatu, to jest proste - wystarczy zamienić na ciąg formatu. Z concat, trzeba dodatkowego kodu. Upewnić się, że nie brzmi jak nic wielkiego w tym konkretnym przykładzie, ale ekstrapolacji.

Odpowiedział 23/08/2008 o 21:07
źródło użytkownik

głosy
84

Spróbuj tego kodu.

Jest to nieco zmodyfikowana wersja kodu.
1. usunąłem Console.WriteLine jak to prawdopodobnie kilka rzędów wielkości wolniejszego niż to, co staram się zmierzyć.
2. Zaczynam się Stoper przed pętli i zatrzymanie go zaraz po tym jak ja nie tracę precyzji, jeśli funkcja przyjmuje na przykład 26,4 kleszczy do wykonania.
3. Sposób podzielić wynik przez niektórych iteracjach myliłem. Zobacz, co się dzieje, jeśli masz 1000 milisekund i 100 milisekund. W obu sytuacjach, dostaniesz 0 ms po podzieleniu go 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);

To są moje wyniki:

1000000 x wynik = string.Format ( "{0} {1}" p.FirstName, p.LastName); trwało: 618ms - kleszcze 2213706
1000000 x wynik = (p.FirstName + "" + p.LastName); wzięli: 166ms - 595610 kleszcze

Odpowiedział 20/08/2008 o 17:40
źródło użytkownik

głosy
54

Ojej - po przeczytaniu jednego z pozostałych odpowiedzi próbowałem odwrócić kolejność operacji - tak wykonywania konkatenacji, potem z 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

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

Oto wyniki biegu gdzie operacje są ukończone więcej niż jeden raz. Próbowałem zmieniając rozkazy ale rzeczy generalnie według tych samych zasad, 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 serie tej samej metody (I refactored kod na 3 sposoby) są stopniowo szybciej. Najszybszy wydaje się Console.WriteLine Sposób (String.Concat (...)), a następnie normalnym konkatenacji, a następnie sformatowane operacji.

Początkowe opóźnienie przy starcie jest prawdopodobnie inicjalizacji konsoli Stream, jak umieszczenie Console.WriteLine ( „Start”), zanim pierwsza operacja przynosi wszystkie czasy z powrotem do linii.

Odpowiedział 20/08/2008 o 09:45
źródło użytkownik

głosy
34

Struny są niezmienne, to znaczy tyle mały kawałek pamięci służy kółko w kodzie. Dodawanie tych samych dwóch ciągów razem i tworząc ten sam nowy ciąg w kółko, nie wpływa pamięć. Net jest na tyle mądry, żeby używać tego samego odniesienia pamięci. Dlatego Twój kod nie naprawdę sprawdzić różnicę między tymi dwoma metodami Concat.

Spróbuj tego na rozmiar:

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

Wyjście próbki:

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
Odpowiedział 13/11/2012 o 02:13
źródło użytkownik

głosy
22

Szkoda biednych tłumaczy

Jeśli wiesz, aplikacja pozostanie w języku angielskim, to w porządku, z wyjątkiem zegar tyka. Jednak wielu kulturach zazwyczaj zobaczyć lastName Book Nazwa w, na przykład, adresy.

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

Odpowiedział 30/11/2009 o 22:11
źródło użytkownik

głosy
14

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 ława:

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, którego odpowiedź oznaczyć jako odpowiedź :)

Odpowiedział 20/08/2008 o 17:16
źródło użytkownik

głosy
9

Łączenie ciągów jest w porządku w prosty scenariusz takiego - jest bardziej skomplikowana z niczego bardziej skomplikowanego niż że nawet Nazwisko, Imię. Z formatem widać na pierwszy rzut oka, co ostateczna struktura łańcucha będzie po odczytaniu kodu z konkatenacji staje się prawie niemożliwe, aby natychmiast rozpoznać wynik końcowy (z wyjątkiem bardzo prosty przykład jak ten).

Co oznacza, że ​​na dłuższą metę jest to, że po powrocie do dokonania zmiany formatu łańcucha, będziesz też mieć możliwość pop i wprowadzić kilka korekt do tekstu formatu, czy zmarszczki swoje czoło i ruszyć wokół wszystkich rodzaje akcesorów nieruchomości zmieszane z tekstem, co jest bardziej prawdopodobne, aby przedstawić problemy.

Jeśli używasz .NET 3.5 można wykorzystać metodę rozszerzenia jak ten i uzyskać łatwy płynących, off 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że zdecydować, że aby utrzymać zdrowo struny w swojej aplikacji, którą chcesz przenieść je do pliku zasobów do lokalizowania lub po prostu do statycznego pomocnika. To będzie o wiele łatwiejsze do osiągnięcia, jeśli masz konsekwentnie używanych formatów, a kod może być po prostu refactored użyć coś jak

string name = String.Format(ApplicationStrings.General.InformalUserNameFormat,this.FirstName,this.LastName);
Odpowiedział 19/08/2008 o 16:56
źródło użytkownik

głosy
7

Dla bardzo proste manipulacje użyję konkatenacji, ale gdy pojawi się za 2 lub 3 elementów Format staje się bardziej stosowne IMO.

Innym powodem jest to, że wolą String.Format .NET ciągi są niezmienne i robi to w ten sposób tworzy mniej tymczasowe / kopie pośrednie.

Odpowiedział 19/08/2008 o 16:50
źródło użytkownik

głosy
6

A ja całkowicie zrozumieć preferencje styl i podniósł konkatenacji dla mojej pierwszej odpowiedzi częściowo oparty na moich własnych preferencji, część mojej decyzji oparto na myśl, że powiązanie byłoby szybciej. Tak, z ciekawości, ja testowałem to i wyniki były zdumiewające, zwłaszcza dla takiego małego łańcucha.

Stosując następujący kod:

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

Mam 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

Stosując metodę formatowania jest ponad 100 razy wolniej !! Łączenie nawet nie rejestruje się jako 1ms, co jest, dlaczego wyjście zegar tyka, jak również.

Odpowiedział 19/08/2008 o 17:02
źródło użytkownik

głosy
5

Począwszy od C # 6.0 interpolowana ciągów mogą być wykorzystane do tego, co upraszcza formatu jeszcze zrobić.

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

Interpolowana wyrażenie ciąg wygląda ciąg szablonu, który zawiera wyrażeń. Interpolowana wyrażenie łańcuchowe tworzy ciąg poprzez zastąpienie wyrażenia zawarte z represenations toString wyników wyrażeń.

Interpolowane struny mają podobną wydajność do String.Format, ale lepszą czytelność i krótszą składnię, ze względu na fakt, że wartości i wyrażenia są włożone w linii.

Proszę zapoznać się również z tym dotnetperls artykułu na interpolację strun.

Jeśli szukasz domyślny sposób sformatować ciągi, to sens pod względem czytelności i wydajności (z wyjątkiem jeśli mikrosekund ma zamiar dokonać zmian w swoim konkretnym przypadku stosowania).

Odpowiedział 07/08/2015 o 23:32
źródło użytkownik

głosy
5

Lepszym Test będzie oglądać swoją pamięć za pomocą Perfmon i liczniki pamięci CLR. W moim rozumieniu jest to, że cały powód chcesz użyć String.Format zamiast tylko łączenie ciągów, ponieważ ciągi są niezmienne, jesteś niepotrzebnie obciążając śmieciarza z ciągów czasowych, które muszą zostać odzyskane w następnym przejściu.

StringBuilder i String.Format, chociaż potencjalnie mniejsza, są bardziej wydajne pamięci.

Co jest tak źle o łańcuchów znaków?

Odpowiedział 22/09/2008 o 15:27
źródło użytkownik

głosy
5

Do podstawowego połączonego łańcucha znaków, ja generalnie użyć drugiego stylu - bardziej czytelne i prostsze. Jednakże, jeśli robię bardziej skomplikowaną kombinację ciąg zwykle wybierają String.Format.

String.Format oszczędza na wiele cytatów i plusy ...

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

Tylko kilka charicters zapisane, ale myślę, że w tym przykładzie, format sprawia, że ​​znacznie czystsze.

Odpowiedział 19/08/2008 o 16:55
źródło użytkownik

głosy
5

Generalnie wolę tych pierwszych, jak zwłaszcza gdy struny dostać długo może być znacznie łatwiejsze do odczytania.

Drugą korzyścią jest to wierzę, jeden z wyników, jak ta ostatnia faktycznie wykonuje 2 oświadczenia tworzenia ciąg przed zdanym ciąg metody Console.Write. String.Format wykorzystuje StringBuilder pod kołdrą jak sądzę, tak wiele powiązań, unika.

Należy jednak zauważyć, że jeśli parametry są przechodzącą w celu String.Format (i innych takich metod jak Console.Write) są typy wartości, a następnie zostaną one zapakowane zanim przeszedł w, które mogą dostarczyć swoje przeboje z wydajnością. Blogu na ten temat tutaj .

Odpowiedział 19/08/2008 o 16:53
źródło użytkownik

głosy
4

W tydzień od teraz 19 sierpnia 2015, kwestia ta będzie dokładnie siedmiu (7) lat. Obecnie istnieje lepszy sposób to robi. Lepiej pod względem konserwacji, jak nie zrobić każdy test wydajności w porównaniu do zaledwie łączenie ciągów (ale to ma znaczenie w tych czasach? Kilka milisekund różnicę?). Nowy sposób to zrobić z C # 6.0 :

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

Ta nowa funkcja jest lepszy , IMO, a właściwie lepiej w naszym przypadku , jak mamy kodów, gdzie budujemy querystrings których wartość zależy od kilku czynników. Wyobraź sobie jeden ciągu kwerendy gdzie 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)

można zapisać w ten sposób i to jest łatwiejsze do odczytania:

var qs=$"q1={someVar}&q2={anotherVarWithLongName}&q3={var3}&q4={var4}&q5={var5}&q6={var6}";
Odpowiedział 12/08/2015 o 03:18
źródło użytkownik

głosy
4

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

Odpowiedział 07/06/2009 o 15:50
źródło użytkownik

głosy
4

I przełącz na podstawie czytelności. Wolę opcję formatowania, gdy pojawia się jakiś tekst wokół zmiennych. W tym przykładzie:

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

Ci zrozumieć sens nawet bez nazw zmiennych, natomiast concat jest bałagan z cytatami i + znaki i dezorientuje oczy:

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

(Pożyczyłem przykład Mike'a bo lubię)

Jeśli ciąg formatu nie znaczy wiele bez nazwy zmiennych, muszę użyć concat:

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

Opcja Format sprawia mi odczytać nazwy zmiennych i mapować je do odpowiednich numerów. Opcja concat nie wymaga. Jestem nadal mylone przez cytaty i + znaków, ale alternatywą jest gorsza. Rubin?

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

Wydajność mądry, spodziewam opcja Format być wolniejsze następnie concat, ponieważ Format wymaga ciąg być analizowany . Nie pamiętam konieczności optymalizacji tego rodzaju instrukcji, ale gdybym to zrobił, to patrzę na stringmetodach jak Concat()i Join().

Drugą zaletą formatu jest to, że ciąg formatu można umieścić w pliku konfiguracyjnym. Bardzo przydatny z komunikatów o błędach i tekstu interfejsu.

Odpowiedział 13/05/2009 o 09:35
źródło użytkownik

głosy
4

Chciałbym użyć String.Format, ale chciałbym również mieć ciąg w formacie plików zasobów, więc może być zlokalizowane w innych językach. Za pomocą prostego ciąg concat nie pozwala, aby to zrobić. Oczywiście jeśli przyzwyczajenie kiedykolwiek trzeba zlokalizować ten ciąg, nie jest to powód do myślenia. To naprawdę zależy od tego, co jest na łańcuch.

Jeśli to będzie pokazywał użytkownika, użyję String.Format więc mogę zlokalizować, jeśli trzeba - i FxCop będzie sprawdzanie pisowni to dla mnie, tak na wszelki wypadek :)

Jeśli zawiera numery lub jakiekolwiek inne rzeczy non-string (np datę), chciałbym użyć String.Format, ponieważ daje mi większą kontrolę nad formatowaniem .

Jeśli to do budowy podobnego zapytania SQL, użyję Linq .

Jeśli na łączenie ciągów wewnątrz pętli, użyję StringBuilder , aby uniknąć problemów z wydajnością.

Jeśli jest to dla jakiegoś wyjścia użytkownik przyzwyczajenie zobaczyć, i nie będzie wpływać wydajność użyję String.Format bo jestem w zwyczaju korzystania z niej w każdym razie, a ja po prostu do tego przyzwyczaić :)

Odpowiedział 19/08/2008 o 17:06
źródło użytkownik

głosy
4
  1. Formatowanie jest „NET” sposób to zrobić. Niektóre narzędzia refactoring (Refactor!) Dla jednego nawet zaproponować byłaby kod concat stylu korzystania z styl formatowania.
  2. Formatowanie jest łatwiejsza do optymalizacji kompilatora (chociaż druga będzie prawdopodobnie refactored użyć metody „Concat”, która jest szybko).
  3. Formatowanie jest zwykle jaśniejsze czytać (zwłaszcza z „wyszukane” formatowania).
  4. Formatowanie oznacza ukrytych połączeń do „.ToString” na wszystkich zmiennych, co jest dobre dla czytelności.
  5. Według „Efektywne C #” .NET „WriteLine” i implementacje „format” są pomieszane, że Autobox wszystkie typy wartość (co jest złe). „Efektywne C #” radzi, aby wykonać „.ToString” wywołuje jednoznacznie, który IMHO jest podrobiony (patrz komentarz Jeffa )
  6. W tej chwili formatowanie podpowiedzi typu nie są sprawdzane przez kompilator, w wyniku błędów wykonawczych. Jednak to może zostać zmienione w przyszłych wersjach.
Odpowiedział 19/08/2008 o 16:59
źródło użytkownik

głosy
3

Jeśli masz do czynienia z czymś, co musi być łatwy do odczytania (i to jest najbardziej code), będę trzymać się z przeciążeniem operatora wersji, chyba że:

  • Kod musi być wykonany miliony razy
  • Robisz ton concats (ponad 4 tony)
  • Kod jest ukierunkowane na Compact Framework

W co najmniej dwóch z tych okoliczności, chciałbym użyć StringBuilder zamiast.

Odpowiedział 22/09/2008 o 15:43
źródło użytkownik

głosy
2

Ponieważ nie sądzę, odpowiedź tutaj obejmować wszystko, chciałbym zrobić mały dodatek tutaj.

Console.WriteLine(string format, params object[] pars)wzywa string.Format. Znak „+” oznacza ciąg konkatenacji. Nie sądzę, to zawsze ma do czynienia z klasą; Staram się mieszać tych dwóch stylów w zależności od kontekstu, w jakim jestem.

Krótka odpowiedź

Decyzja jesteś obliczu ma zrobić z przydziału strun. Postaram się zrobić to proste.

Załóżmy, że masz

string s = a + "foo" + b;

Jeśli wykonasz to oceni, co następuje:

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

tmptutaj nie jest to zmienna lokalna, ale jest to tymczasowy dla JIT (jest popychany na stos IL). Jeśli naciśniesz ciąg na stosie (takich jak ldstrIL dla literałów), można umieścić odniesienie do wskaźnika ciąg na stosie.

W chwili, gdy nazywają concatto odwołanie staje się problemem, ponieważ nie ma żadnego odniesienia ciąg dostępne, które zawiera zarówno ciągi. Oznacza to, że .NET musi przydzielić nowy blok pamięci, a następnie wypełnić go z dwóch ciągów. Powodem jest to problem, ponieważ jest alokacja jest stosunkowo drogie.

Która zmienia się pytanie: w jaki sposób można zmniejszyć liczbę concatoperacji?

Więc odpowiedź jest szorstki: string.Formatdla> 1 concats, „+” będzie działać dobrze dla 1 concat. A jeśli nie dbają o robienie mikro optymalizacje wydajności, string.Formatbędzie działać dobrze w przypadku ogólnym.

Uwaga na temat Kultury

A jeszcze coś, co nazywa kultura ...

string.Formatumożliwia korzystanie CultureInfow formatowaniu. Prosty operatora „+” używa bieżącej kulturę.

Jest to szczególnie ważna uwaga jeśli piszesz formatów plików i f.ex. doubleWartości, które „Dodaj” na sznurku. Na różnych maszynach, może skończyć się z różnych ciągów jeśli nie korzystają string.Formatz jawnym CultureInfo.

F.ex. rozważyć, co się stanie, jeśli zmieni „” za „” podczas zapisywania pliku oddzielone przecinkami wartościami ... w języku Separator dziesiętny jest przecinek, dzięki czemu użytkownik może po prostu uzyskać «śmiesznym» zaskoczenia.

Więcej Odpowiedź Drobiazgowy

Jeśli nie znasz dokładnej wielkości napisu wcześniej, najlepiej użyć politykę tak, aby overallocate bufory używać. Przestrzeń luzu jest najpierw wypełniony, po którym dane są kopiowane.

Uprawy środki przydzielania nowego bloku pamięci i kopiuje się stare dane dla nowego buforu. Stary blok pamięci może być zwolniony. Otrzymasz dolnej linii w tym punkcie: rośnie jest kosztowna operacja.

Najbardziej praktycznym sposobem, aby to zrobić jest użycie politykę zawyżone. Najczęstszą polityką jest overallocate buforów uprawnień 2. Oczywiście, trzeba zrobić to trochę mądrzejsza (ponieważ nie ma sensu, aby rozwijać z 1,2,4,8 jeśli już wiesz, czego potrzebujesz 128 znaków ), ale pojawi się obraz. Polisa zapewnia nie trzeba zbyt wiele kosztownych operacji I opisanych powyżej.

StringBuilderJest to klasa, która w zasadzie overallocates bazowego bufor potęgi dwójki. string.Formatwykorzystuje StringBuilderpod maską.

To sprawia, że ​​decyzja podstawowy kompromis pomiędzy overallocate-i-dopisywania (-Wiele) (w / wo kultury) lub po prostu przeznaczyć-i-append.

Odpowiedział 22/05/2015 o 09:19
źródło użytkownik

głosy
2

Niezłe!

Właśnie dodane

        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 to nawet szybciej (chyba string.Concat nazywany jest w obu przypadkach, ale pierwszy z nich wymaga pewnego rodzaju tłumaczeniu).

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
Odpowiedział 20/08/2008 o 19:07
źródło użytkownik

głosy
2

Wolę drugie jako dobrze, ale nie mam żadnych racjonalnych argumentów w tej chwili na poparcie tego stanowiska.

Odpowiedział 19/08/2008 o 16:51
źródło użytkownik

głosy
2

Myślę, że to zależy w dużej mierze od tego, jak skomplikowana jest wyjście. I mają tendencję do wyboru w zależności od tego scenariusz sprawdza się najlepiej w tym czasie.

Wybrać odpowiednie narzędzie oparte na pracy: D Niezależnie wygląda najczystszych!

Odpowiedział 19/08/2008 o 16:50
źródło użytkownik

głosy
1

Zgodnie z materiału prep MCSD Microsoft proponuje zastosowanie operatora + gdy mamy do czynienia z bardzo niewielką liczbą powiązań, (prawdopodobnie od 2 do 4). I nadal nie wiem dlaczego, ale jest to coś do rozważenia.

Odpowiedział 04/07/2009 o 21:31
źródło użytkownik

głosy
1

Byłem ciekaw, gdzie StringBuilder stał z tych testów. 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 kleszcze
Concat: 356 kleszczy
Concat: 411 kleszcze
Concat: 299 kleszcze
Concat: 266 kleszcze
Format: 5269 kleszcze
Format: 954 kleszcze
Format: 1004 kleszcze
Format: 984 kleszcze
Format: 974 kleszcze
StringBuilder: 629 kleszcze
StringBuilder: 484 kleszcze
StringBuilder: 482 kleszcze
StringBuilder: 508 kleszcze
StringBuilder: 504 kleszcze
Odpowiedział 22/09/2008 o 15:56
źródło użytkownik

głosy
1

Pierwszy z nich (format) wygląda lepiej dla mnie. To jest bardziej czytelny i nie stwarzają dodatkowych obiektów tymczasowych ciągów.

Odpowiedział 23/08/2008 o 20:55
źródło użytkownik

głosy
1

Aha, i tylko pod względem kompletności, oto kilka kleszcze szybciej niż normalnie konkatenacji:

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));
Odpowiedział 20/08/2008 o 09:38
źródło użytkownik

głosy
1

Zawsze poszedł string.Format () trasą. Będąc w stanie przechowywać w zmiennych formatach takich jak np Nathana jest wielką zaletą. W niektórych przypadkach mogę dołączyć zmienną, ale po ponad 1 zmienna jest łączone I byłaby użyć formatowania.

Odpowiedział 19/08/2008 o 20:16
źródło użytkownik

głosy
1

I faktycznie jak pierwszy z nich, bo gdy istnieje wiele zmiennych, przemieszanych z tekstu wydaje się łatwiejsze do odczytania dla mnie. Plus, łatwiej jest radzić sobie z cytatami podczas korzystania z string.Format (), uh, formatu. Oto przyzwoity analiza z łańcuchów znaków.

Odpowiedział 19/08/2008 o 16:57
źródło użytkownik

głosy
1

Osobiście, drugi jak wszystko używasz jest rzędu bezpośredniego będzie to wyjście w. Podczas gdy w pierwszym trzeba dopasować do {0} i {1} z właściwym var, który jest łatwy do bałagan.

Przynajmniej nie jest tak źle, jak sprintf C ++, gdzie jeśli masz typ zmiennej złego cała sprawa będzie wysadzić.

Ponadto, ponieważ drugi jest wszystko inline i nie musi wykonywać żadnych wyszukiwanie i zastępowanie dla wszystkich {0} rzeczy, ten ostatni powinien być szybciej ... choć nie wiem na pewno.

Odpowiedział 19/08/2008 o 16:49
źródło użytkownik

głosy
0

Faktycznie, te testy wpadłem wczoraj, ale było już późno, więc nie kładę moje odpowiedzi.

Najważniejsze wydaje się, że biorą zarówno w tym samym czasie średnio. Zrobiłem test ponad 100000 iteracji.

Postaram z StringBuilder, jak również i będę pisać kod i wyniki, gdy wracam do domu.

Odpowiedział 20/08/2008 o 14:43
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more