programing

문자열 출력: C#의 형식 또는 콘캣?

easyjava 2023. 9. 16. 10:05
반응형

문자열 출력: C#의 형식 또는 콘캣?

문자열을 출력하거나 컨캣하고 싶다고 가정해 보겠습니다.다음 스타일 중 어떤 것을 선호하십니까?

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

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

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

당신은 형식을 사용합니까 아니면 단순히 줄을 사용합니까?당신이 가장 좋아하는 것은 무엇입니까?이것들 중 하나가 당신의 눈을 아프게 합니까?

하나만 사용하고 다른 하나는 사용하지 않는 합리적인 주장이 있습니까?

저는 두 번째로 하겠습니다.

이렇게 많은 사람들이 가장 빨리 실행되는 코드를 즉시 찾고 싶어한다는 것이 놀랍습니다.백만 번의 반복을 처리하는 데 1초도 걸리지 않는 경우, 최종 사용자에게 이러한 작업이 어떤 방식으로든 눈에 띌 수 있습니까? 그럴 가능성은 없습니다.

조기 최적화 = FAIL.

께로 .String.Format단지 건축적 관점에서 가장 합리적이기 때문에 옵션을 선택할 수 있습니다.문제가 될 때까지 성능에 신경 쓰지 않습니다(만약 문제가 된다면).한 번에 백만 명의 이름을 연결해야 합니까?물론 화면에 다 들어가지는 않을 것입니다...)

나중에 고객이 표시 여부를 구성할 수 있도록 변경을 원할 경우 고려합니다."Firstname Lastname"아니면"Lastname, Firstname."형식 옵션을 사용하면 형식 문자열을 쉽게 바꿀 수 있습니다.콘캣과 함께라면 추가 코드가 필요합니다.물론 이것은 이 예에서 큰 문제로 들리지는 않지만 추측해 볼 수 있습니다.

이 코드를 사용해 보세요.

코드를 약간 수정한 것입니다.

  1. 콘솔을 제거했습니다.WriteLine은 아마 제가 측정하려는 것보다 몇 배는 느릴 것이기 때문입니다.
  2. 루프를 시작하기 전에 Stopwatch를 시작하고 바로 종료합니다. 이렇게 하면 함수를 실행하는 데 26.4 틱이 필요할 경우 정밀도를 잃지 않습니다.
  3. 결과를 일부 반복으로 나누는 방법이 틀렸습니다.1,000밀리초와 100밀리초가 있으면 어떻게 되는지 확인합니다.두 경우 모두 1,000,000으로 나누면 0ms가 나옵니다.

코드:

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

결과는 다음과 같습니다.

1000000 x 결과 = 문자열. {jp("{0} {1}"), p. Name, p187, p.Last : - 2213706 ); 촬영: 618ms - 2213706
x = (1000000 x과= (p).이름 + " + p.(Last : 166ms - ); 취함: 166ms - 595610

오 이런 - 다른 응답 중 하나를 읽은 후에 작업 순서를 바꾸려고 했습니다. 그래서 연결을 먼저 수행한 다음 String을 수행합니다.서식...

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

따라서 작업의 순서가 크게 달라지거나, 처음 작업은 항상 훨씬 더 느려집니다.

다음은 작업이 두 번 이상 완료된 런의 결과입니다.주문 변경을 시도했지만, 첫 번째 결과가 무시되면 일반적으로 같은 규칙을 따릅니다.

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

동일한 방법의 후속 실행(코드를 3가지 방법으로 재분사)이 점진적으로 빨라지는 것을 볼 수 있습니다.가장 빠른 것은 콘솔인 것 같습니다.쓰기 줄(String)Concat(...) 메서드에 이어 일반 연결, 그리고 포맷된 작업입니다.

초기 시작 지연은 콘솔을 배치할 때 콘솔 스트림을 초기화하는 것일 수 있습니다.첫 번째 작업이 모든 시간을 줄로 되돌리기 전에 쓰기 라인("시작!")을 작성합니다.

문자열은 불변이며, 이는 코드에서 동일한 작은 메모리 조각이 반복적으로 사용됨을 의미합니다.동일한 두 문자열을 함께 추가하고 동일한 새 문자열을 반복적으로 생성해도 메모리에 영향을 미치지 않습니다.Net은 동일한 메모리 참조를 사용할 수 있을 만큼 충분히 똑똑합니다.그러므로 당신의 코드는 두 콘캣 방법의 차이를 제대로 테스트하지 못합니다.

사이즈는 이 옷을 입어보세요.

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

샘플 출력:

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

불쌍한 번역가들을 불쌍히 여겨라.

응용프로그램이 영어로 유지된다는 을 알고 있다면, 좋아요, 시계 눈금을 저장하세요.그러나 많은 문화들은 보통 주소와 같은 곳에서 성을 봅니다.

을 합니다.string.Format() 만약 할 가 모국어가 곳에 갈 것입니다

다음은 10만 번 이상 반복한 결과입니다.

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

여기 벤치 코드가 있습니다.

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

그래서 누구의 답장을 답으로 표기할지 모르겠어요 :)

문자열을 연결하는 것은 이와 같은 간단한 시나리오에서는 괜찮습니다. 이보다 더 복잡한 것, 심지어 성(Last Name), 이름(First Name)까지 더 복잡합니다.코드를 읽을 때 문자열의 최종 구조가 무엇인지 한눈에 알 수 있으며, 연결을 사용하면 최종 결과를 즉시 식별하는 것이 거의 불가능해집니다(이와 같은 매우 간단한 예는 제외).

결국 문자열 형식을 변경하기 위해 돌아왔을 때 갑자기 나타나 문자열을 몇 가지 수정하거나, 눈썹을 찡그리며 텍스트와 혼합된 모든 종류의 속성 액세스 장치를 이동하기 시작하면 문제가 발생할 가능성이 더 높다는 것을 의미합니다.

사용하시는 분들은.NET 3.5 이와 같은 확장 방법을 사용하면 다음과 같이 커프 구문에서 쉽게 이동할 수 있습니다.

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

마지막으로, 애플리케이션이 복잡해짐에 따라 애플리케이션에서 문자열을 정상적으로 유지하기 위해 해당 문자열을 리소스 파일로 이동하여 현지화하거나 단순히 정적 도우미로 이동할 수 있습니다.이것은 만약 당신이 지속적으로 사용되는 포맷을 가지고 있다면 훨씬 더 쉽게 달성될 것이고, 당신의 코드는 다음과 같은 것을 사용하기 위해 꽤 간단하게 리팩토링 될 수 있습니다.

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

C#부터 시작하기 6.0 인터폴레이션된 문자열을 사용하여 이 작업을 수행할 수 있으므로 형식이 더욱 단순해집니다.

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

보간된 문자열 식을 식을 포함하는 템플릿 문자열처럼 보입니다.보간된 문자열 표현식은 포함된 표현식을 표현식 결과의 ToString 표현식으로 대체하여 문자열을 만듭니다.

보간된 문자열의 성능은 String과 비슷합니다.형식이지만 값과 표현식이 인라인으로 삽입되어 있기 때문에 가독성이 향상되고 구문이 짧아집니다.

문자열 보간에 대한 이 dotnetperls 기사도 참조하시기 바랍니다.

문자열을 포맷하는 기본 방법을 찾고 있다면 가독성 및 성능 측면에서 타당합니다(마이크로초가 특정 사용 사례에 영향을 미칠 경우는 제외).

아주 간단한 조작을 위해서는 연접을 사용하고 싶지만, 2~3가지 요소를 넘어서면 IMO가 더 적합합니다.

String을 선호하는 또 다른 이유.형식은 입니다.NET 문자열은 불변이며 이렇게 하면 임시/중간 복사본이 적게 생성됩니다.

저는 스타일 선호도를 완전히 이해하고 부분적으로 제 자신의 선호도에 근거하여 첫 번째 답변에 연접을 선택했지만, 제 결정의 일부는 연접이 더 빠를 것이라는 생각에 근거했습니다.그래서 호기심으로 테스트를 해봤더니 결과가 충격적이었습니다. 특히 그런 작은 끈에 대해서 말이죠.

다음 코드 사용:

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

저는 다음과 같은 결과를 얻었습니다.

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

포맷 방법을 사용하면 100배 이상 느려집니다!!연결이 1ms로 등록되지도 않아서 타이머 틱도 출력합니다.

기본적인 문자열 연결을 위해, 저는 일반적으로 읽기 쉽고 간단한 두 번째 스타일을 사용합니다.하지만 좀 더 복잡한 스트링 조합을 할 경우 보통 스트링을 선택합니다.포맷.

String.형식은 많은 따옴표와 더하기 기호를 저장합니다.

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

몇 개의 문자만 저장할 수 있지만, 이 예에서는 형식이 훨씬 더 깨끗하다고 생각합니다.

이제부터 일주일 후인 2015년 8월 19일, 이 질문은 정확히 7살이 될 것입니다.이제 더 나은 방법이 있습니다.단순히 문자열을 연결하는 것보다 성능 테스트를 전혀 하지 않았기 때문에 유지보수성 측면에서 더 좋습니다(하지만 요즘에는 문제가 됩니까? 몇 밀리초의 차이가 있습니까?C# 6.0으로 새로운 작업 방식:

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

IMO, 이 새로운 기능은 값이 일부 요소에 따라 달라지는 쿼리 문자열을 구축하는 코드가 있기 때문에 더 낫습니다.우리가 6개의 인수를 가지고 있는 하나의 쿼리 문자열을 상상해 보세요.예를 들어, a를 하는 대신에:

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

in은 다음과 같이 쓸 수 있고 읽기가 더 쉽습니다.

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

더 좋은 테스트는 Perfmon과 CLR 메모리 카운터를 사용하여 메모리를 보는 것입니다.당신이 String을 사용하려는 모든 이유를 이해합니다.문자열을 연결하는 형식이 아닌 형식은 문자열이 불변하기 때문에 다음 패스에서 회수해야 하는 임시 문자열로 가비지 수집기에 불필요한 부담을 주는 것입니다.

StringBuilder 및 String.포맷은 잠재적으로 느리지만 메모리 효율성이 더 높습니다.

문자열 연결의 무엇이 그렇게 나쁜가요?

일반적으로 전자를 선호합니다. 특히 줄이 길어지면 읽기가 훨씬 쉬워지기 때문입니다.

다른 이점은 공연 중 하나라고 생각한다는 것입니다. 후자는 마지막 문자열을 전달하기 전에 실제로 2개의 문자열 생성 문장을 수행하기 때문입니다.Console.Write방법.String.Format내가 생각하는 커버 아래에 StringBuilder를 사용하므로 여러 연결을 피할 수 있습니다.

만약 가 가 과 해야 에 하는 해야 에 하는 String.Format(및 콘솔과 같은 기타 방법).쓰기)는 값 유형이며 전달되기 전에 상자에 저장되므로 고유의 성능 히트를 제공할 수 있습니다.여기에 대한 블로그 게시물.

  1. 형식은 "입니다.NET' 방식으로.특정 리팩터 도구(Refactor! for one)는 포맷 스타일을 사용하기 위해 콘캣 스타일 코드를 리팩터하는 것을 제안할 것입니다.
  2. 포맷은 컴파일러에 최적화하기가 더 쉽습니다(단, 두 번째는 'Concat' 메서드를 사용하기 위해 리팩토링됩니다).
  3. 포맷은 일반적으로 읽기에 더 선명합니다(특히 "화려한" 포맷을 사용합니다).
  4. 서식은 '로 암묵적으로 호출하는 것을 의미합니다.모든 변수에 'ToString'을 사용하면 가독성에 좋습니다.
  5. "Effective C#"에 따르면.NET 'WriteLine' 및 'Format' 구현은 엉망이 되었습니다. 모든 값 유형을 자동으로 저장합니다(이는 잘못된 것입니다)."Effective C#"은 '을(를) 수행할 것을 권고합니다.ToString' 은 명시적으로 전화를 걸며, IMHO는 이를 허위로 보고 있습니다(Jeff의 참조).
  6. 현재 형식 유형 힌트는 컴파일러에서 확인되지 않으므로 런타임 오류가 발생합니다.그러나 이는 향후 버전에서 수정될 수 있습니다.

저는 가독성에 따라 선택합니다.변수 주변에 텍스트가 있을 때 포맷 옵션을 선호합니다.이 예에서는 다음과 같습니다.

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

당신은 변수 이름이 없어도 의미를 이해하는 반면, 콘캣은 따옴표와 + 기호로 어수선하고 내 눈을 혼란스럽게 합니다.

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

(마음에 들어서 마이크의 예를 빌렸습니다.)

변수 이름이 없는 형식 문자열이 큰 의미가 없다면 concat을 사용해야 합니다.

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

포맷 옵션을 사용하면 변수 이름을 읽고 해당 숫자에 매핑할 수 있습니다.콘캣 옵션은 그것을 요구하지 않습니다.따옴표와 + 기호가 아직도 헷갈리긴 하지만, 대안은 더 심각합니다.루비?

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

성능 측면에서 볼 때, 포맷 옵션은 문자열을 파싱해야 하므로 콩캣보다 느릴 것으로 예상합니다.이런 종류의 지시를 최적화해야 했던 기억은 없지만, 만약 그렇다면,string과 같은 Concat()그리고.Join().

형식의 또 다른 장점은 형식 문자열을 구성 파일에 넣을 수 있다는 점입니다.오류 메시지와 UI 텍스트에 매우 편리합니다.

저는 을 합니다.String.Format할 수 간단한 줄을 사용하는 것은 당신이 그렇게 할 수 없습니다.분명히, 만약 당신이 그 문자열을 현지화할 필요가 없다면, 이것은 그것에 대해 생각할 이유가 아닙니다.실제로 끈이 무엇을 위한 것이냐에 달려있습니다.

만약 사용자에게 보여질 것이라면, 저는String.Format필요하면 현지화 할 수 있도록 하고 혹시 모르니 FxCop에서 맞춤법 검사를 해줄 것입니다 :)

숫자나 문자열이 아닌 다른 것(예: 날짜)이 포함되어 있다면,String.Format포맷을 더 잘 조절할 수 있게 해주기 때문입니다.

SQL 같은 쿼리를 만들기 위한 것이라면, 저는 Linq를 사용할 것입니다.

루프 내에서 문자열을 연결하는 경우 성능 문제를 피하기 위해 StringBuilder를 사용합니다.

어떤 출력을 위한 것이라면 사용자가 볼 수 없고 성능에 영향을 미치지 않을 것입니다.어차피 사용하는 습관이 있고 익숙하기 때문에 포맷 :)

읽기 쉬운 내용을 다루고 있다면(대부분의 코드가 이에 해당됨), 다음과 같은 경우가 아니라면 연산자 오버로드 버전을 사용할 것입니다.

  • 코드는 수백만 번 실행해야 합니다.
  • 당신은 엄청난 양의 콩캣(4개 이상은 1톤)을 하고 있습니다.
  • 코드는 Compact Framework를 대상으로 합니다.

이 중 적어도 두 가지 상황에서는 StringBuilder를 대신 사용할 것입니다.

결과를 현지화하려면 String을 선택합니다.서로 다른 자연어들은 같은 순서로 데이터를 가지고 있지 않을 수도 있기 때문에 형식은 필수적입니다.

이것은 출력이 얼마나 복잡한지에 따라 크게 좌우된다고 생각합니다.저는 어떤 시나리오가 가장 효과적인지 선택하는 편입니다.

작업에 따라 적합한 도구를 선택합니다 :D 어느 것이든 가장 깨끗해 보입니다!

저는 두 번째 것도 선호하지만 현재로서는 그 입장을 지지할 만한 합리적인 주장이 없습니다.

좋아요!

방금 추가했습니다.

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

그리고 그것은 훨씬 더 빠릅니다(줄이라고 추측합니다).Concat은 두 예에서 모두 불리지만 첫 번째 예에서는 일종의 번역이 필요합니다.).

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

여기서의 답이 모든 것을 다 다루는 것은 아니라고 생각하기 때문에, 여기서 약간의 추가를 하고자 합니다.

Console.WriteLine(string format, params object[] pars)string.Format는 문자열합니다. '+'는 문자열 연결을 의미합니다.저는 이것이 항상 스타일과 관련이 있다고 생각하지 않습니다. 저는 제가 처한 상황에 따라 두 스타일을 혼합하는 경향이 있습니다.

단답형

당신이 직면한 결정은 문자열 할당과 관련이 있습니다.간단하게 해보겠습니다.

가지고 있다고 치자.

string s = a + "foo" + b;

이를 실행하면 다음과 같이 평가됩니다.

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

tmp여기서는 실제 로컬 변수는 아니지만 JIT(IL 스택에서 푸시됨)에 대한 임시 변수입니다.예에는우을예(우예:는에 :ldstr리터럴의 IL)에서 스택의 문자열 포인터에 대한 참조를 넣습니다.

이 ㅇㅇㅇ을 concat두 문자열을 모두 포함하는 문자열 참조가 없기 때문에 이 참조가 문제가 됩니다.은을 합니다.NET은 새 메모리 블록을 할당한 다음 두 개의 문자열로 채워야 합니다.이것이 문제가 되는 이유는 할당이 상대적으로 비싸기 때문입니다.

그러면 질문이 다음과 같이 바뀝니다. Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ Δ concat작전?

그렇다면, 대략적인 대답은 다음과 같습니다.string.Format1마리 이상의 콘캣에 대해서는 '+'가 1마리 이상의 콘캣에 대해서도 정상적으로 작동합니다.그리고 마이크로 성능 최적화 작업에 신경 쓰지 않는다면,string.Format일반적인 경우에는 잘 될 겁니다

문화에 관한 노트

그 다음엔 문화라는 것이 있습니다.

string.Format를 사용할 수 있게 해줍니다.CultureInfo당신의 서식에 따라.단순 연산자 '+'는 현재의 문화를 사용합니다.

과 f를 작성하는 경우 특히 중요한 언급입니다. f.ex. f.ex.를 에는 더욱 입니다.double문자열에 '추가'하는 값입니다.른서면른이될수다지다수fundp'hettu,st서n이지른면string.Format으로를 CultureInfo.

F.ex. 쉼표로 구분된 값 파일을 작성하는 동안 '.'를 '로 변경하면 어떻게 되는지 고려해 보십시오.네덜란드어로 소수점 구분자는 쉼표이므로 사용자는 '재미있는' 놀라움을 느낄 수 있습니다.

보다 자세한 답변

문자열의 정확한 크기를 미리 모르는 경우 이와 같은 정책을 사용하여 사용하는 버퍼를 초과 할당하는 것이 좋습니다.여유 공간이 먼저 채워지고, 그 후에 데이터가 복사됩니다.

성장이란 새로운 메모리 블록을 할당하고 이전 데이터를 새 버퍼에 복사하는 것을 의미합니다.그러면 이전 메모리 블록을 해제할 수 있습니다.이 시점에서 핵심을 파악할 수 있습니다. 성장하는 것은 비용이 많이 드는 작업입니다.

가장 실용적인 방법은 전체 위치 정책을 사용하는 것입니다.가장 일반적인 정책은 2의 거듭제곱에서 버퍼를 초과 할당하는 것입니다.물론 그것보다 조금 더 똑똑하게 해야 하지만 (128 Char가 필요하다는 것을 이미 알고 있다면 1,2,4,8에서 성장하는 것은 말이 안 되기 때문에) 이해할 수 있습니다.이 정책을 통해 위에서 설명한 값비싼 작업을 너무 많이 수행할 필요가 없습니다.

StringBuilder는 기본적으로 기본 버퍼를 2의 거듭제곱으로 초과 할당하는 클래스입니다.string.Format사용하다StringBuilder

이를 통해 과할당 및 추가(-복수) 또는 할당 및 추가(-.o. culture) 간의 기본적인 균형 조정을 결정할 수 있습니다.

텍스트에 변수가 많이 섞여 있을 때 더 쉽게 읽을 수 있기 때문에 저는 사실 첫 번째 것을 좋아합니다.또한 문자열을 사용할 때 따옴표를 다루기가 더 쉽습니다.포맷(), 어, 포맷.다음은 문자열 연결에 대한 적절한 분석입니다.

저는 항상 줄을 섰습니다.경로 형식을 지정합니다.Nathan의 예와 같은 변수에 형식을 저장할 수 있다는 것은 큰 장점입니다.어떤 경우에는 변수를 추가할 수도 있지만, 한 번 이상 변수가 연결되면 포맷을 사용하기 위해 리팩터를 사용합니다.

아, 그리고 단지 완전성을 위해, 다음은 일반적인 연결보다 몇 번 빠른 틱입니다.

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

제가 보기에는 첫 번째 것(형식)이 더 낫습니다.읽기 쉬우며 임시 문자열 개체를 추가로 만들지 않습니다.

이 테스트로 StringBuilder가 어디에 서 있는지 궁금했습니다.아래 결과...

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

결과:

콘캣 : 406 진드기콘캣 : 356 진드기콘캣 : 411 진드기콘캣 : 299 진드기콘캣 : 266 진드기형식: 5269 진드기형식: 954 진드기형식 : 1004 진드기형식: 984개 틱형식: 974개 틱StringBuilder: 629 진드기StringBuilder: 484 진드기StringBuilder: 482 진드기StringBuilder: 508 진드기StringBuilder: 504 진드기

MCSD 준비 자료에 따르면 마이크로소프트는 매우 적은 수의 연결(아마도 2~4개)을 처리할 때 + 연산자를 사용할 것을 제안합니다.왜 그런지는 아직 잘 모르겠지만, 고려해 볼 일입니다.

가장 읽기 쉬운 은 C#의 문자열 보간 기능을 사용하는 것일 것입니다.6.0:

Console.WriteLine($"{p.FirstName} {p.LastName}");

성능은 "+"를 사용하는 것과 비슷합니다.

언급URL : https://stackoverflow.com/questions/16432/string-output-format-or-concat-in-c

반응형