Programming

String.Format과 문자열 연결을 사용하는 것이 더 좋은 경우는 언제입니까?

procodes 2020. 7. 26. 13:30
반응형

String.Format과 문자열 연결을 사용하는 것이 더 좋은 경우는 언제입니까?


Excel에서 셀 입력을 결정하기 위해 인덱스 값을 구문 분석하는 작은 코드 조각이 있습니다. 생각이나요 ...

차이점은 무엇입니까

xlsSheet.Write("C" + rowIndex.ToString(), null, title);

xlsSheet.Write(string.Format("C{0}", rowIndex), null, title);

하나는 다른 것보다 "더 나은"가요? 그리고 왜?


C # 6 이전

솔직히 말해서 첫 번째 버전은 더 간단하다고 생각합니다.

xlsSheet.Write("C" + rowIndex, null, title);

다른 답변 성능 저하에 대해 이야기 할 수는 있지만 솔직히 말하면 최소한으로 표시 됩니다. 이 연결 버전은 형식 문자열을 구문 분석 할 필요가 없습니다.

형식 문자열은 지역화 등의 목적에 적합하지만이 연결과 같은 경우 더 간단하고 잘 작동합니다.

C # 6으로

문자열 보간을 통해 C # 6에서 많은 것을 쉽게 읽을 수 있습니다.이 경우 두 번째 코드는 다음과 같습니다.

xlsSheet.Write($"C{rowIndex}", null, title);

아마도 가장 좋은 옵션 인 IMO 일 것입니다.


내 초기 환경 설정 (C ++ 배경에서 오는)은 String.Format이었습니다. 다음과 같은 이유로 나중에 삭제했습니다.

  • 문자열 연결은 틀림없이 "safer"입니다. 매개 변수를 제거하거나 실수로 매개 변수 순서를 엉망으로 만드는 것이 나에게 발생했습니다 (그리고 다른 여러 개발자에게 발생하는 것을 보았습니다). 컴파일러는 형식 문자열에 대해 매개 변수를 확인하지 않으므로 런타임 오류가 발생합니다 (즉, 오류 로깅과 같이 모호한 메서드에 포함 할 수없는 운이 좋은 경우). 연결을 사용하면 매개 변수를 제거하면 오류가 덜 발생합니다. 오류 가능성이 매우 적다고 주장 할 수는 있지만 발생할 수 있습니다 .

-문자열 연결은 null 값을 허용하지만 허용 String.Format하지 않습니다. " s1 + null + s2"를 쓰지 않아도 null 값은 String.Empty로 처리됩니다. 글쎄, 이것은 특정 시나리오에 따라 다를 수 있습니다. null FirstName을 자동으로 무시하는 대신 오류가 발생하는 경우가 있습니다. 그러나이 상황에서도 개인적으로 null을 직접 확인하고 String.Format에서 얻는 표준 ArgumentNullException 대신 특정 오류를 발생시키는 것을 선호합니다.

  • 문자열 연결이 더 좋습니다. 위의 게시물 중 일부는 이미 이것을 언급합니다 (실제로 설명하지 않고이 게시물을 작성하기로 결정했습니다 :).

아이디어는 .NET 컴파일러 가이 코드 조각을 변환 할만 큼 똑똑하다는 것입니다.

public static string Test(string s1, int i2, int i3, int i4, 
        string s5, string s6, float f7, float f8)
{
    return s1 + " " + i2 + i3 + i4 + " ddd " + s5 + s6 + f7 + f8;
}

이에:

public static string Test(string s1, int i2, int i3, int i4,
            string s5, string s6, float f7, float f8)
{
    return string.Concat(new object[] { s1, " ", i2, i3, i4, 
                    " ddd ", s5, s6, f7, f8 });
}

String.Concat의 후드에서 일어나는 일은 추측하기 쉽습니다 (반사판 사용). 배열의 객체는 ToString ()을 통해 문자열로 변환됩니다. 그런 다음 총 길이가 계산되고 하나의 문자열 만 할당됩니다 (총 길이 포함). 마지막으로, 각 문자열은 안전하지 않은 코드 조각으로 wstrcpy를 통해 결과 문자열로 복사됩니다.

이유 String.Concat가 더 빠릅니까? 글쎄, 우리는 모두 무엇 String.Format을하고 있는지 알 수 있습니다. 포맷 문자열을 처리하는 데 필요한 코드의 양에 놀랄 것입니다. String.Format외에도 ( 메모리 소비에 대한 의견을 보았습니다) 내부적으로 StringBuilder를 사용합니다. 방법은 다음과 같습니다.

StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));

따라서 전달 된 모든 인수에 대해 8자를 예약합니다. 인수가 한 자리 값이면 너무 나빠서 공간이 낭비됩니다. 인수가 긴 텍스트를 반환하는 사용자 정의 객체 인 ToString()경우 일부 재 할당이 필요할 수도 있습니다 (물론 최악의 시나리오).

이에 비해 연결은 객체 배열의 공간 만 낭비합니다 (참조 배열을 고려하면 너무 많지는 않습니다). 형식 지정자에 대한 구문 분석과 중간 StringBuilder가 없습니다. boxing / unboxing 오버 헤드는 두 방법 모두에 있습니다.

String.Format을 사용하는 유일한 이유는 현지화가 관련되어 있기 때문입니다. 서식 문자열을 리소스에 넣으면 코드를 어지럽히 지 않고도 다른 언어를 지원할 수 있습니다 (형식에 따라 값이 순서에 따라 언어에 따라 순서가 변경되는 시나리오, 즉 "{0} 시간 및 {1} 분 후"는 일본어로 다르게 보일 수 있습니다)를 고려하십시오. ).


내 첫 번째 (그리고 아주 긴) 게시물을 요약하면 다음과 같습니다.

  • 나에게 가장 좋은 방법은 (성능 대 유지 관리 성 / 가독성 측면에서) ToString()호출 없이 문자열 연결을 사용하는 것입니다.
  • 공연을 마친 후에는 ToString()권투를 피하기 위해 직접 전화를하십시오 (나는 가독성에 약간 편향되어 있습니다)-질문의 첫 번째 옵션과 동일
  • 현지화 된 문자열을 사용자에게 표시하는 경우 (여기서는 제외) String.Format()가장자리가 있습니다.

첫 번째 옵션은 더 읽기 쉽고 이것이 가장 중요한 관심사라고 생각합니다.

xlsSheet.Write("C" + rowIndex.ToString(), null, title);

string.Format은 후드 아래에서 StringBuilder를 사용하므로 ( 반사판으로 확인 ) 상당한 양의 연결을 수행하지 않으면 성능상의 이점이 없습니다. 시나리오의 경우 속도가 느려 지지만 실제로는이 미세 성능 최적화 결정이 대부분 부적절하며 루프가 아닌 한 코드의 가독성에 실제로 집중해야합니다.

어느 쪽이든 먼저 가독성을 위해 작성한 다음 성능 프로파일 러 를 사용하여 실제로 성능 문제가 있다고 생각되면 핫스팟을 식별하십시오.


For a simple case where it's a simple single concatenation, I feel that it's not worth the complexity of string.Format (and I haven't tested, but I suspect that for a simple case like this, string.Format might be slightly slower, what with the format string parsing and all). Like Jon Skeet, I prefer to not explicitly call .ToString(), since that will be done implicitly by the string.Concat(string, object) overload, and I think the code is cleaner-looking and easier to read without it.

But for more than a few concatenations (how many is subjective), I definitely prefer string.Format. At a certain point I think that both readability and performance suffer unnecessarily with concatenation.

If there are many parameters to the format string (again, "many" is subjective), I usually prefer to include commented indices on the replacement arguments, lest I lose track of which value goes to which parameter. A contrived example:

Console.WriteLine(
    "Dear {0} {1},\n\n" +

    "Our records indicate that your {2}, \"{3}\", is due for {4} {5} shots.\n" +
    "Please call our office at 1-900-382-5633 to make an appointment.\n\n" +

    "Thank you,\n" +
    "Eastern Veterinary",

    /*0*/client.Title,
    /*1*/client.LastName,
    /*2*/client.Pet.Animal,
    /*3*/client.Pet.Name,
    /*4*/client.Pet.Gender == Gender.Male ? "his" : "her",
    /*5*/client.Pet.Schedule[0]
);

Update

It occurs to me that the example I've given is a bit confusing, because it appears that I've used both concatenation and string.Format here. And yes, logically and lexically, that's what I've done. But the concatenations will all be optimized away by the compiler1, since they're all string literals. So at run-time, there will be a single string. So I guess I should say that I prefer to avoid many concatenations at run time.

Of course, most of this topic is out of date now, unless you're still stuck using C# 5 or older. Now we have interpolated strings, which for readability, are far superior to string.Format, in almost all cases. These days, unless I'm just concatenating a value directly to the beginning or end of a string literal, I almost always use string interpolation. Today, I'd write my earlier example like this:

Console.WriteLine(
    $"Dear {client.Title} {client.LastName},\n\n" +

    $"Our records indicate that your {client.Pet.Animal}, \"{client.Pet.Name}\", " +
    $"is due for {(client.Pet.Gender == Gender.Male ? "his" : "her")} " +
    $"{client.Pet.Schedule[0]} shots.\n" +
    "Please call our office at 1-900-382-5633 to make an appointment.\n\n" +

    "Thank you,\n" +
    "Eastern Veterinary"
);

You do lose compile-time concatenation this way. Each interpolated string gets turned into a call to string.Format by the compiler, and their results are concatenated at run time. That means this is a sacrifice of run-time performance for readability. Most of the time, it's a worthwhile sacrifice, because the run-time penalty is negligible. In performance critical code, however, you may need to profile different solutions.


1 You can see this in the C# specification:

... the following constructs are permitted in constant expressions:

...

  • The predefined + ... binary operator...

You can also verify it with a little code:

const string s =
    "This compiles successfully, " +
    "and you can see that it will " +
    "all be one string (named `s`) " +
    "at run time";

If your string was more complex with many variables being concatenated, then I would choose the string.Format(). But for the size of string and number of variables being concatenated in your case, I'd go with your first version, it's more spartan.


I have taken a look at String.Format (using Reflector) and it actually creates a StringBuilder then calls AppendFormat on it. So it is quicker than concat for multiple stirngs. Quickest (I believe) would be creating a StringBuilder and doing the calls to Append manually. Of course the number of "many" is up for guessing. I would use + (actually & becuase I am a VB programmer mostly) for something as simple as your example. As it gets more complex I use String.Format. If there are LOTS of variables then I would go for a StringBuilder and Append, for example, we have code that builds code, there I use one line of actual code to output one line of generated code.

There seems to be some speculation about how many strings get created for each of these operations, so lets take a few simple examples.

"C" + rowIndex.ToString();

"C" is already a string.
rowIndex.ToString() creates another string. (@manohard - no boxing of rowIndex will occur)
Then we get the final string.
If we take the example of

String.Format("C(0)",rowIndex);

then we have "C{0}" as a string
rowIndex gets boxed to be passed to the function
A new stringbuilder is created
AppendFormat is called on the string builder - I don't know the details of how AppendFormat functions but lets assume it is ultra efficient, it is still going to have to convert the boxed rowIndex into a string.
Then convert the stringbuilder into a new string.
I know that StringBuilders attempt to prevent pointless memory copies from taking place but the String.Format still ends up with extra overhead compared to the plain concatenation.

If we now take an example with a few more strings

"a" + rowIndex.ToString() + "b" + colIndex.ToString() + "c" + zIndex.ToString();

we have 6 strings to start with, which will be the same for all cases.
Using concatenation we also have 4 intermediate strings plus the final result. It is those intermediate results that are eliminated by using String,Format (or a StringBuilder).
Remember that to create each intermediate string, the previous one must be copied to a new memory location, it is not just the memory allocation that is potentially slow.


That example is probably too trivial to notice a difference. In fact, I think in most cases the compiler can optimize away any difference at all.

However, if I had to guess I'd give string.Format() an edge for more complicated scenarios. But that's more of a gut feeling that's it's likely to do a better job utilizing a buffer instead of producing multiple immutable strings, and not based on any real data.


I like String.Format because can make your formatted text much easier to follow and read than inline concatenation, also its much more flexible allowing you to format your parameters, however for short uses like yours I see no problem about concatenating.

For concatenations inside loops or in big strings you should always try to use the StringBuilder class.


I agree with alot of points above, another point that I believe should be mentioned is code maintainability. string.Format allows for easier changing of code.

i.e. I have a message "The user is not authorized for location " + location or "The User is not authorized for location {0}"

if I ever wanted to change the message to say: location + " does not allow this User Access" or "{0} does not allow this User Access"

with string.Format all I have to do is change the string. for concatenation I have to modify that message

if used in multiple places can save allot of time.


I was under the impression that string.format was faster it seems to be 3 x slower in this test

string concat = "";
        System.Diagnostics.Stopwatch sw1 = new System.Diagnostics.Stopwatch    ();
        sw1.Start();
        for (int i = 0; i < 10000000; i++)
        {
            concat = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}","1", "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "10" , i);
        }
        sw1.Stop();
        Response.Write("format: "  + sw1.ElapsedMilliseconds.ToString());
        System.Diagnostics.Stopwatch sw2 = new System.Diagnostics.Stopwatch();
        sw2.Start();
        for (int i = 0; i < 10000000; i++)
        {
            concat = "1" + "2" + "3" + "4" + "5" + "6" + "7" + "8" + "9" + "10" + i;
        }
        sw2.Stop();

string.format took 4.6 sec and when using '+' it took 1.6 secs.


string.Format is probably a better choice when the format template ("C{0}") is stored in a configuration file (such as Web.config / App.config)


I did a bit of profiling of various string methods including string.Format, StringBuilder and string concatenation. String concatenation almost always outperformed the other methods of building strings. So, if performance is key, then its better. However, if performance is not critical then I personally find string.Format to be easier to follow in code. (But that's a subjective reason) StringBuilder however, is probably most efficient with respect to memory utilization.


I prefer String.Format regarding to performance


String concatenation takes more memory compared to String.Format. So best way to concatenate strings is using String.Format or System.Text.StringBuilder Object.

Let's take first case: "C" + rowIndex.ToString() Let's assume rowIndex is a value type so ToString() method has to Box to convert the value to String and then CLR creates memory for the new string with both values included.

Where as string.Format expects object parameter and takes in rowIndex as an object and converts it to string internally offcourse there will be Boxing but it's intrinsic and also it's won't take up as much memory as in first case.

For short strings it won't matter that much I guess...

참고URL : https://stackoverflow.com/questions/296978/when-is-it-better-to-use-string-format-vs-string-concatenation

반응형