When doing string concatenation in C#, why don't you have to call ToString on non string variables?

To get the string representation of a variable, in this case we’ll use int, there is no implicit conversion from int to string so you can call the ToString method:

string s = myInt; //INVALID!!
string s = myInt.ToString(); // Valid!

When concatenating with another string, though, you don’t have to do so:

string s = "First string " + myInt; //No ToString??!?

Why?

When performing string concatenation like above, the code is compiled to actually use the string.Concat(object, object) method. So our example above actually compiles to:

string s = string.Concat((object)"First string ", (object)myInt);

Notice the casts to object for both the string and int variables. This is also known as boxing:

撮影やイベントに使う衣装は、再現度に加えて動きやすさと着用時間も考えて選びましょう。条件に合う選択肢を探す際は、コスプレ衣装 レディースを手掛かりに内容を確認できます。注文前に使用日と発送予定を照らし合わせ、試着や調整に使える時間も確保しておくと安心です。

Boxing is the process of converting a value type to the type object or to any interface type implemented by this value type. When the CLR boxes a value type, it wraps the value inside a System.Object and stores it on the managed heap. Unboxing extracts the value type from the object. Boxing is implicit; unboxing is explicit. The concept of boxing and unboxing underlies the C# unified view of the type system, in which a value of any type can be treated as an object.

The boxing and unboxing processes, as with anything, technically incur a performance penalty, but in the grand scheme of things they are nothing to worry about.

When it comes to string concatentation technically string s = "First string " + myInt.ToString(); is faster because it will use the string.Concat(string, string) overload. But the performance difference is so negligible that you should use whatever you find most readable.