views:

3919

answers:

30

Let's say that you want to output or concat strings, what style do you prefer:

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

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

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

Do you rather use format or do you simply concat strings? What is your favorite? Is one of these hurting your eyes?

Do you have any rational arguments to use one and not the other?

I'd go for the second one.

A: 

Personally, the second one as everything you are using is in the direct order it will be output in. Whereas with the first you have to match up the {0} and {1} with the proper var, which is easy to mess up.

At least it's not as bad as the C++ sprintf where if you get the variable type wrong the whole thing will blow up.

Also, since the second is all inline and it doesn't have to do any searching and replacing for all the {0} things, the latter should be faster... though I don't know for sure.

Adam Haile
+1  A: 

I think this depends heavily on how complex the output is. I tend to choose whichever scenario works best at the time.

Pick the right tool based on the job :D Whichever looks cleanest!

mercutio
+3  A: 

For very simple manipulation I'd use concatenation, but once you get beyond 2 or 3 elements Format becomes more appropriate IMO.

Another reason to prefer String.Format is that .NET strings are immutable and doing it this way creates fewer temporary/intermediate copies.

James D
A: 

I prefer the second as well but I have no rational arguments at this time to support that position.

Chuck
+4  A: 

Generally I prefer the former, as especially when the strings get long it can be much easier to read.

The other benefit is I believe one of performance, as the latter actually performs 2 string creation statements before passing the final string to the Console.Write method. String.Format uses a StringBuilder under the covers I believe, so multiple concatenations are avoided.

It should be noted however that if the parameters you are passing in to String.Format (and other such methods like Console.Write) are value types then they will be boxed before passed in, which can provide its own performance hits. Blog post on this here.

samjudson
That blog post is now at:http://jeffbarnes.net/blog/post/2006/08/08/Avoid-Boxing-When-Using-StringFormat-with-Value-Types.aspx. I suffer from insufficient rep to edit.
Richard Slater
+2  A: 

For basic string concatenation, I generally use the second style - easier to read and simpler. However, if I am doing a more complicated string combination I usually opt for String.Format.

String.Format saves on lots of quotes and pluses...

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

Only a few charicters saved, but I think, in this example, format makes it much cleaner.

Mike
+6  A: 

Concatenating strings is fine in a simple scenario like that - it is more complicated with anything more complicated than that, even LastName, FirstName. With the format you can see, at a glance, what the final structure of the string will be when reading the code, with concatenation it becomes almost impossible to immediately discern the final result (except with a very simple example like this one).

What that means in the long run is that when you come back to make a change to your string format, you will either have the ability to pop in and make a few adjustments to the format string, or wrinkle your brow and start moving around all kinds of property accessors mixed with text, which is more likely to introduce problems.

If you're using .NET 3.5 you can use an extension method like this one and get an easy flowing, off the cuff syntax like this:

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

Finally, as your application grows in complexity you may decide that to sanely maintain strings in your application you want to move them into a resource file to localize or simply into a static helper. This will be MUCH easier to achieve if you have consistently used formats, and your code can be quite simply refactored to use something like

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

I actually like the first one because when there are a lot of variables intermingled with the text it seems easier to read to me. Plus, it is easier to deal with quotes when using the string.Format(), uh, format. Here is decent analysis of string concatenation.

adparadox
+1  A: 
  1. Formatting is the “.NET” way of doing it. Certain refactoring tools (Refactor! for one) will even propose to refactor the concat-style code to use the formatting style.
  2. Formatting is easier to optimize for the compiler (although the second will probably be refactored to use the 'Concat' method which is fast).
  3. Formatting is usually clearer to read (especially with “fancy” formatting).
  4. Formatting means implicit calls to '.ToString' on all variables, which is good for readability.
  5. According to “Effective C#”, the .NET 'WriteLine' and 'Format' implementations are messed up, they autobox all value types (which is bad). “Effective C#” advises to perform '.ToString' calls explicitly, which IMHO is bogus (see Jeff's posting)
  6. At the moment, formatting type hints are not checked by the compiler, resulting in runtime errors. However, this could be amended in future versions.
Konrad Rudolph
+6  A: 

While I totally understand the style preference and picked concatenation for my first answer partly based on my own preference, part of my decision was based on the thought that concatenation would be faster. So, out of curiosity, I tested it and the results were staggering, especially for such a small string.

Using the following code:

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

I got the following results:

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

Using the formatting method is over 100 times slower!! Concatenation didn't even register as 1ms, which is why I output the timer ticks as well.

Adam Haile
But of course you should perform the operation more than once to get measurements.
erikkallen
+2  A: 

I'd use the String.Format, but I would also have the format string in the resource files so it can be localised for other languages. Using a simple string concat doesn't allow you to do that. Obviously if you wont ever need to localise that string, this isn't a reason to think about. It really depends on what the string is for.

If it's going to be showed to the user, I'd use String.Format so I can localize if I need to - and FxCop will spell check it for me, just in case :)

If it contains numbers or any other non-string things (e.g. dates), I'd use String.Format because it gives me more control over the formatting.

If it's for building a query like SQL, I'd use Linq.

If for concatenating strings inside a loop, I'd use StringBuilder to avoid performance problems.

If it's for some output the user wont see, and isn't going to effect performance I'd use String.Format because I'm in the habit of using it anyway and I'm just used to it :)

Wilka
A: 

I've always gone the string.Format() route. Being able to store formats in variables like Nathan's example is a great advantage. In some cases I may append a variable but once more than 1 variable is being concatenated I refactor to use formatting.

Scott Muc
A: 

Oh, and just for completeness, the following is a few ticks faster than normal concatenation:

Console.WriteLine(String.Concat(p.FirstName," ",p.LastName));
samjudson
+10  A: 

Oh dear - after reading one of the other replies I tried reversing the order of the operations - so performing the concatenation first, then the 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

So the order of the operations makes a HUGE difference, or rather the very first operation is ALWAYS much slower.

Here is the results of a run where operations are completed more than once. I have tried changing the orders but things generally follow the same rules, once the first result is ignored:

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.Contact(FirstName, " ", LastName); took: 0ms - 142 ticks
Bill Gates
String.Contact(FirstName, " ", LastName); took: 0ms - 117 ticks

As you can see subsequent runs of the same method (I refactored the code into 3 methods) are incrementally faster. The fastest appears to be the Console.WriteLine(String.Contact(...)) method, followed by normal concatenation, and then the formatted operations.

The initial delay in startup is likely the initialisation of Console Stream, as placing a Console.Writeline("Start!") before the first operation brings all times back into line.

samjudson
A: 

Actually, I ran these tests yesterday, but it was getting late so I didnt put my responses.

The bottom line seems that they take both the same time on average. I did the test over 100000 iterations.

I'll try with StringBuilder as well, and I'll post the code and results when I get home.

Philippe
+12  A: 

Here are my results over 100000 itrations:

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

And here is the bench code:

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

So, I don't know who's reply to mark as an answer :)

Philippe
Why is the background blue for this answer?
@yossi it's blue because the answerer is the same as the asker
Davy8
+15  A: 
Michał Piaskowski
A: 

Nice one!

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

And it is even faster (I guess string.Concat is called in both examples, but the first one requires some sort of translation).

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
Philippe
A: 

The first one (format) looks better to me. It's more readable and you are not creating extra temporary string objects.

Rismo
+10  A: 

I'm amazed that so many people immediately want to find the code that executes the fastest. If ONE MILLION iterations STILL takes less than a second to process, is this really going to be in ANY WAY noticeable to the end user? Not very likely.

Premature optimization = FAIL.

I'd go with the String.Format option, simply because it makes the most sense from an architectural standpoint. I don't care about the performance until it actually becomes an issue (and if it did, I'd ask myself: Do I really need to concatenate a million names at once? Surely they won't all fit on the screen...)

Consider if your customer later wants to change it so that he can configure wether to display "Firstname Lastname" or "Lastname, Firstname". With the Format option, this is easy - just swap out the format string. With the concat, you'll need extra code. Sure that doesn't sound like a big deal in this particular example, but extrapolate.

Fredrik Kalseth
+1  A: 

A better test would be to watch your memory using Perfmon and the CLR memory counters. My understanding is that the whole reason you want to use String.Format instead of just concatenating strings is, since strings are immutable, you are unnecessarily burdening the garbage collector with temporary strings that need to be reclaimed in the next pass.

StringBuilder and String.Format, although potentially slower, are more memory efficient.

What is so bad about string concatenation?

David Hill
I Agree; every string operation creates a new copy of the string. All that memory will be reclaimed by the garbage collector sooner or later. So, allocating a lot of strings may come back to bite you later.
Marnix van Valen
+1  A: 

If you're dealing with something that needs to be easy to read (and this is most code), I'd stick with the operator overload version UNLESS:

  • The code needs to be executed millions of times
  • You're doing tons of concats (more than 4 is a ton)
  • The code is targeted towards the Compact Framework

Under at least two of these circumstances, I would use StringBuilder instead.

plinth
A: 

I was curious where StringBuilder stood with these tests. Results below...

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

Results:

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
spoulson
A: 

I choose based on readability. I prefer the format option when there's some text around the variables. In this example:

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

you understand the meaning even without variable names, whereas the concat is cluttered with quotes and + signs and confuses my eyes:

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

(I borrowed Mike's example because I like it)

If the format string doesn't mean much without variable names, I have to use concat:

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

The format option makes me read the variable names and map them to the corresponding numbers. The concat option doesn't require that. I'm still confused by the quotes and + signs, but the alternative is worse. Ruby?

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

Performance wise, I expect the format option to be slower then the concat, since format requires the string to be parsed. I don't remember having to optimize this kind of instruction, but if I did, I'd look at string methods like Concat() and Join().

The other advantage with format is that the format string can be put in a configuration file. Very handy with error messages and UI text.

DonkeyMaster
+2  A: 

If you intend to localise the result, then String.Format is essential because different natural languages might not even have the data in the same order.

Christian Hayter
A: 

According to the MCSD prep material, Microsoft suggests using the + operator when dealing with a very small number of concatenations (probably 2 to 4). I'm still not sure why, but it's something to consider.

Babak Naffas
A: 

hi how are you ?

sdfsdf
A: 
Console.WriteLine("User {0} accessed {1} on {2}.", 
                   user.Name, fileName, timestamp);
is the best met
  • List item

hod

sdfsdf
+2  A: 

Pity the poor translators

If you know your application will stay in English, then fine, save the clock ticks. However, many cultures would usually see Lastname Firstname in, for instance, addresses.

So use string.Format(), especially if you're going to ever have your application go anywhere that English is not the first language.

Jeremy McGee
+1  A: 

It really depends on your usage pattern.
A detailed benchmark between string.Join, string,Concat and string.Format can be found here: String.Format Isn't Suitable for Intensive Logging

Liran