Now I'm going to add an example to illustrate how the compiler treats them, because there are many problems in some other answers (edit: note that most of these confusions are now deleted / edited):
bool value = true; int channel = 1; String s = String.Format(":Channel{0}:Display {1}", channel, value ? "ON" : "OFF");
The last line compiles as:
String s = String.Format(":Channel{0}:Display {1}", new object[2] {(object)channel, value ? "ON" : "OFF")};
pay attention to the creation of the array and the βboxβ for the int channel , and, of course, the additional parsing needed to search for {0} / {1} .
Now number 2:
bool value = true; String channel = "1"; string s = ":Channel" + channel + ":Display " + (value ? "ON" : "OFF");
The last line compiles as:
string s = string.Concat(":Channel", channel, ":Display ", value ? "ON" : "OFF");
there is no array, no field ( channel now a string) and no parsing. Overload public static string string.Concat(string,string,string,string) ; string.Concat runs very efficiently by first assigning a size string to the right and then rewriting, etc.
In most codecs, everything is fine. The second version is technically more efficient (no box, no array, no parsing), but it's a big pain if you ever want to internationalize later. In most applications, you will not notice the differences between them. Parsing is fast, and the block / array is cheaply collected as objects with zero zero. But cheap is not free.