[suggestion] Compiler should call ToString on non-string types used with string.operator+
#10.966 aperta il 29 apr 2016
Metriche repository
- Star
- (20.414 star)
- Metriche merge PR
- (Merge medio 6g 17h) (256 PR mergiate in 30 g)
Descrizione
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