-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Description
Background
There's a lot of code out there that uses string concatenation to append arbitrary objects to strings, like so:
public class MutablePerson
{
public string Name { get; set; }
public int Age { get; set; }
public override void ToString()
{
return this.Name + " is " + this.Age + " years old.";
}
}
At compile-time, Roslyn tranforms calls to string.operator+
to string.Concat
to avoid allocating intermediary strings, so what we end up with is this:
public override void ToString()
{
return string.Concat(this.Name, " is ", this.Age, " years old.");
}
Unfortunately, string.Concat
only accepts object
parameters, meaning that Age
(which is an int) is implicitly boxed when it is passed into the function. Of course, boxing is no good for performance, so if the developer wants to avoid this, he/she has to explicitly call ToString
on the variable, e.g.
return this.Name + " is " + this.Age.ToString() + " years old.";
and the compiler will do the right thing and omit the box
instruction.
An example of where this really became a pain was dotnet/corefx#8025, where a bunch of ToString
calls had to be added to avoid boxing on each item.
Proposal
Instead of calling the string.Concat
overloads that accept objects, the compiler should exclusively generate code targeting the ones accepting a string. For value types, the code generated would coerce the variable into a string via ToString
:
"foo" + someStruct + "bar"; // what was written
string.Concat("foo", someStruct.ToString(), "bar"); // what was emitted
Existing strings could simply be concatenated directly, without a ToString
call (same behavior as today):
"quux" + someString; // what was written
string.Concat("quux", someString); // what was emitted
And for other reference types, a ToString
would be emitted with an extra null check:
"baz" + someClass; // what was written
string.Concat("baz", someClass?.ToString()); // what was emitted