stringとobjectを+演算子で連結できたらしい

そんなばかな。
アニソン三昧以来起動していなかったPCを思わず立ち上げて確認。

string a = "foo";
// string b = a + 123.ToString();
string b = a + 123;
// b == "foo123"

// var c = "bar" + new KeyValuePair<int, bool>(1, true).ToString();
var c = "bar" + new KeyValuePair<int, bool>(1, true);
// c == "bar[1, True]"

ToStringいらないってどういうことなの。

コンパイラの魔法

var test = "foo" + 123;

これをコンパイルして逆アセンブル

nop
ldstr "foo"
ldc.i4.s 123
box [mscorlib]System.Int32
call string [mscorlib]System.String::Concat(object, object)
stloc.0

Concatメソッドが呼ばれています。お、おう。

文字列を連結するメソッドとして、String.Concatメソッドがあります。String.Concatメソッドを使ったときと連結演算子を使ったときの違いは、全くありません。ビルドするとどちらもString.Concatが使われるようになります。

http://dobon.net/vb/dotnet/string/concat.html

このメソッドは、arg0 と arg1 のパラメーターなしの ToString メソッドを呼び出すことによって、arg0 と arg1 を連結します。区切り記号は追加しません。

http://msdn.microsoft.com/ja-jp/library/kbseaaft

なるほど。

仕様の言い分

もしString.Concatを使うからobjectを渡せるというのであれば、その旨が仕様にも書いてあるはず。と思って検索するも見つからない。
代わりにこんなものを発見。

  • 文字列の連結 :


string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);
二項演算子 + のこれらのオーバーロードでは、文字列の連結が実行されます。文字列連結のオペランドが null の場合は、空の文字列に置き換えられます。文字列ではない引数は、object 型から継承された仮想の ToString メソッドを呼び出すことで、文字列形式に変換されます。ToString が null を返す場合は、空の文字列に置き換えられます。
C#言語仕様 Version4.0§7.8.4加算演算子

なるほど・・・毎回ToStringしてたよ・・・

まとめ

string operator +(string x, string y);
string operator +(string x, object y);
string operator +(object x, string y);

値型の場合はボックス化されてしまうのでToStringが用意されているなら先にやっておくのがいいですね。ボックス化のコストは馬鹿にならないってばっちゃが。
ついでに本家.NET Frameworkの実装を見ると、一つでもobjectがあれば全てToStringした上で全パラメータstringのオーバーロードに流しているようなので云々。
それにしても「複数の文字列から新しい文字列を生成するには+演算子を使います」といった説明はあっても、object渡せるって説明が仕様以外に見つからなかったのはどういう・・・