4

I was googling for best c# string concatenation, and I found this at microsoft c# code conventions: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions

Use the + operator to concatenate short strings, as shown in the following code:

string displayName = nameList[n].LastName + ", " + nameList[n].FirstName;

But I really prefer (String.Format) "$" for more readability IMHO:

string firstName = "MyName";
string lastName = "MyLastName";
string displayName = $"{lastName}, {firstName}";
Console.WriteLine(displayName); // "MyLastName, MyName"

Can you tip me which one do you think is better one? or is just about personal preference?

Thanks!

Ferus7
  • 707
  • 1
  • 10
  • 23
  • 3
    Both are valid syntax and both are acceptable and it really depends on your personal, team or organization preferences. The question is actually opinion-based. I personally prefer string interpolation (approach 2) for *most* cases, but not always. – Yeldar Kurmangaliyev Jun 28 '17 at 09:54
  • 1
    Concatenating a small number of strings is faster than `String.Format`, but premature optimization is the root of all evil. – Jeroen Mostert Jun 28 '17 at 09:56
  • @Yeldar Kurmangaliyev thank you, i really don´t see the point of using the traditional + operator hmmm – Ferus7 Jun 28 '17 at 09:56
  • @Jeroen Mostert you mean in terms of technical performance or readability? – Ferus7 Jun 28 '17 at 09:58
  • I mean as in "consuming less CPU cycles". Do I myself eagerly concatenate strings now that we have interpolation? No, of course not. If I had some tight loop where string formatting was the bottleneck, it'd be another matter. – Jeroen Mostert Jun 28 '17 at 10:00
  • When mentioning a source, please include a link to it. I guess that this was contrasting `+` for short strings against the need for StringBuilder. Not `+` against `.Format()`, that really isn't very significant. – H H Jun 28 '17 at 10:01
  • Before asking whether you really need this to be fast, have you run performance tests that pinpoint this as a hot spot in your actual application? – Jon Skeet Jun 28 '17 at 10:01
  • I was just asking like: which one do you use and why? because I'm newbie in C#, and reading "C# in a Nutshell" book, I found "$" utility and get it very useful, but maybe in terms of practices it was oriented for very specifically cases – Ferus7 Jun 28 '17 at 10:07
  • `String.Format` as well as `$` is very sloooooow! Because parsing the format string in runtime. – Alexander Petrov Jun 28 '17 at 11:29
  • 1
    String format is very slow but unless you run lots of iteration i doubt it will be visible. For example we generate millions of words and concatenate them and just from switching from string format to string builder we have went from 5 ish seconds to less than 40 ms. that's on a 4.5 ghz cpu. our reports shows our average user cpu are 2.2ghz. On a 2.8 ghz it was taking more than 10 seconds. Like i said it depend on your usage. – Franck Jun 28 '17 at 12:04
  • I think maybe is worth to lose that bit of performance, and gain more readability – Ferus7 Jun 28 '17 at 12:35

3 Answers3

2

If performance is key String concatenation is better because it always out performs the other methods of building strings.
But String concatenation takes more memory compared to String.Format. So best way to concatenate strings is using String.Format or System.Text.StringBuilder Object

Yousha Aleayoub
  • 4,532
  • 4
  • 53
  • 64
SyMo7amed
  • 368
  • 2
  • 15
2

Use StringBuilder for the best performance. String.Format is also good but not an exact replacement for "+" operator on string.

StringBuilder builder = new StringBuilder();
// Append to StringBuilder.
for (int i = 0; i < 10; i++)
{
    builder.Append(i).Append(" ");
}
Console.WriteLine(builder);

Remember to import namespace:

using System.Text;
Habeeb
  • 7,601
  • 1
  • 30
  • 33
  • " but not an exact replacement for "+" operator on string", so which usage do you mean `String.Format` has? – Ferus7 Jun 28 '17 at 12:33
2

This is over a year old, but top of Google results. Originally I was doing this:

StringBuilder builder = new StringBuilder();
// Append to StringBuilder.
for (int i = 0; i < 10; i++)
{
    builder.Append(i + " ");
}
Console.WriteLine(builder);

Then I thought that's probably defeating the point of using StringBuilder. I started doing it like

StringBuilder builder = new StringBuilder();
// Append to StringBuilder.
for (int i = 0; i < 10; i++)
{
    builder.Append(i);
    builder.Append(" ");
}
Console.WriteLine(builder);

Finally, I realized I can chain methods to have it like @Habeeb. It got me wondering if there's any performance benefits.

$e1 = [Text.StringBuilder]::new()
$e2 = [Text.StringBuilder]::new()

function ef1(){
   Write-Host "Start Date:" (Get-Date)
   for($i=0;$i -lt 100000;$i++){
      $e1.Append("Hello") | Out-Null
      $e1.AppendLine($i.ToString()) | Out-Null
      $e1.Append("World") | Out-Null
      $e1.AppendLine($i.ToString()) | Out-Null
      $e1.Append("More Lines") | Out-Null
      $e1.AppendLine($i.ToString()) | Out-Null
   }
}

function ef2(){
   Write-Host "Start Date:" (Get-Date)
   for($i=0;$i -lt 100000;$i++){
$e1.Append("Hello").AppendLine($i.ToString()).Append("World").AppendLine($i.ToString()).Append("More Lines").AppendLine($i.ToString()) | Out-Null
   }
   Write-Host "End Date:" (Get-Date)
}

This was a rough throw together, and I realize it's in PS. But, ef1 resulted in 17 seconds, and ef2 resulted in 3 seconds (not considering milliseconds here). Unless I'm mistaken, chaining methods is insanely performance improving. (And yes, this is possibly not unique to StringBuilder, but StringBuilder led me to ask this question.)

Update:

Thanks to @cogumel0, I realize now how expensive Out-Null is. Increasing the iterations another digit shows ef1 takes about 4 seconds and ef2 about 1 second. (I also added the missing write end date for ef1.)

$e1 = [Text.StringBuilder]::new()
$e2 = [Text.StringBuilder]::new()

function ef1(){
   Write-Host "Start Date:" (Get-Date)
   for($i=0;$i -lt 1000000;$i++){
      [void] $e1.Append("Hello")
      [void] $e1.AppendLine($i.ToString())
      [void] $e1.Append("World")
      [void] $e1.AppendLine($i.ToString())
      [void] $e1.Append("More Lines")
      [void] $e1.AppendLine($i.ToString())
   }
   Write-Host "Start Date:" (Get-Date)
}

function ef2(){
   Write-Host "Start Date:" (Get-Date)
   for($i=0;$i -lt 1000000;$i++){
[void] $e1.Append("Hello").AppendLine($i.ToString()).Append("World").AppendLine($i.ToString()).Append("More Lines").AppendLine($i.ToString())
   }
   Write-Host "End Date:" (Get-Date)
}
Tyler Montney
  • 1,402
  • 1
  • 17
  • 25
  • 1
    There appears to be (in PS at least) some difference between the two functions - but not in that magnitude. The problem is that piping to `Out-Null` is incredibly expensive. `Out-Null` is a class and you're creating 6 instances of that class per iteration. Each instance then has to invoke 3 methods: `BeginProcessing()` `ProcessRecord()` and `EndProcessing()`. The pipeline is also incredibly expensive. My computer takes exactly the same time as yours to run your code, but replace all ` | Out-Null` with `[void] ` and my computer takes 350ms for ef1 and 130ms for ef2 – cogumel0 Oct 15 '18 at 12:47
  • Good to know, didn't realize Out-Null was that costly. – Tyler Montney Nov 01 '18 at 00:43
  • On another note, never use `Get-Date` when dealing with time sensitive matters. Again you're creating two instances of a class in ef1 and two instances of a class in ef2. Instead use something like `[DateTime]::Now`. The `Now` property returns exactly the same as `Get-Date` but is a static property - does not create an instance of `DateTime` class at all for its invocation. Still, that won't give you an accurate idea of how long something takes to run, so instead I'd suggest using `Measure-Command {}` which gives back a `TimeSpan` object - far more accurate. – cogumel0 Nov 05 '18 at 10:58
  • Right, I wasn't even referencing the milliseconds. I just added enough iterations until it was enough of a gap to see in seconds. The testing was a bit lazy. – Tyler Montney Nov 08 '18 at 21:03