C#で一度に複数の文字列を結合した時の処理時間を計測する

#背景
以前[C#における最速の文字列結合を検証する](https://qiita.com/TD12734/items/fad83dddb8f0452b7d38)という記事を書いてstringの結合は+演算子を用いた物とStringBuilderを用いた物のどちらが速いのかを検証した。
同記事内での検証でStringBuilderの方が速いと結論付けたが、記事のコメントで以下のような~~マサカリ~~指摘を頂いた。

> C#の仕様ではstr s = "a" + "b" + "c"のように定数を一度に複数連結するとコンパイルの時点でs = "abc"に置き換えられるよ:stuck_out_tongue_winking_eye:
だから`定数を一度に複数結合する場合は`StringBuilderでは勝負にならないよ:smile:

つまりこういう事らしい。

```c#
string str = "";
System.Text.StringBuilder Sb = new System.Text.StringBuilder ();

//+演算子による結合
str += "abc";
str = "";
str += "a" + "b" + "c";//コンパイル時点で右辺は"abc"に置き換えられるので、処理時間は上と一緒

//StringBuilderによる結合
Sb.Append ("abc");
str = Sb.ToString ();//「C#における最速の文字列結合を検証する」の検証結果から、str += "abc";と処理時間はほぼ同じ

Sb.Clear ();
Sb.Append ("a").Append ("b").Append ("c");
str = Sb.ToString ();//これだけ遅い
```

しかし、この指摘が事実かどうかは分からない。そこで真偽を確かめるために今回、一度に複数の文字列を結合した場合の処理時間について検証することにした。

#検証内容
以下のコードを使用する。

```c#
using System;

class Class
{
	static void Main ()
	{
		string str = "";//こいつに文字を追加する
		System.Text.StringBuilder Sb = new System.Text.StringBuilder ();//こいつに文字を追加する
		string s0 = "あたいったら最強ね！";//最初に追加する文字
		string s1 = "あたいったら最強ね！";//追加する文字
		const string s2 = "あたいったら最強ね！";//追加する文字、混合の時はこっちを定数にする
		string Result;//表示の時に使う
		int i;
		int p;//処理パターン
		const int n = 100000;//試行回数
		System.Diagnostics.Stopwatch Sw = new System.Diagnostics.Stopwatch ();//処理時間計測用ストップウォッチ
		double TotalTime = 0;

		for (p = 0; p < 39; p++)
		{
			TotalTime = 0;
			for (i = 0; i < n; i++)
			{
				str = "";//文字列とストップウォッチをリセット
				Sb.Clear ();
				Sw.Reset ();
				Sw.Start ();
				switch (p)
				{
				case 0://何もしない
					break;
				case 1://1
					str += s0;
					break;
				case 2:
					Sb.Append (s0);
					break;
				case 3://2
					str += s0 + s2;
					break;
				case 4:
					Sb.Append (s0).Append (s2);
					break;
				case 5://3
					str += s0 + s2 + s1;
					break;
				case 6:
					Sb.Append (s0).Append (s2).Append (s1);
					break;
				case 7://4
					str += s0 + s2 + s1 + s2;
					break;
				case 8:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2);
					break;
				case 9://5
					str += s0 + s2 + s1 + s2 + s1;
					break;
				case 10:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1);
					break;
				case 11://6
					str += s0 + s2 + s1 + s2 + s1 + s2;
					break;
				case 12:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 13://7
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1;
					break;
				case 14:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1);
					break;
				case 15://8
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 16:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 17://9
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1;
					break;
				case 18:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1);
					break;
				case 19://10
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 20:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 21://20
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 22:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 23://30
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 24:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 25://40
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 26:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 27://50
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 28:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 29://60
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 30:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 31://70
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 32:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 33://80
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 34:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 35://80
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 36:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 37://100
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 38:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				}
				Sw.Stop ();
				TotalTime += Sw.Elapsed.TotalMilliseconds;
			}
			//かかった時間を表示
			if (p == 0)
			{
				Result = "空";
			}
			else
			{
				if (p % 2 == 1)
				{
					Result = "str";
				}
				else
				{
					Result = "Sb";
				}
				if (p <= 20)
				{
					Result += Math.Ceiling (p / 2d).ToString ();
				}
				else
				{
					Result += (Math.Ceiling ((p - 18) / 2d) * 10).ToString ();
				}
			}
			//かかった時間を表示
			Console.WriteLine (Result + "：" + (TotalTime / n) + "ms");
		}

		//いずれかのキーを押してコンソールを終了する
		Console.WriteLine ("Press any key to exit.");
		Console.ReadKey ();
	}
}
```

なんだかすっごく頭が悪そうな検証コードになってしまった。横にすっごく長い。
動作の内容は以下のような感じ。

- 同じ値を持つstring s0、s1、s2を一度に計1～100個結合する時間を計測する
- +演算子とStringBuilderを用いた2種類の結合について、処理時間を計測する(StringBuilderの場合はToString()する時間も処理時間に含める)
- 計測はそれぞれ10万回行い、平均の処理時間を実際の処理時間とする
- s0、s1、s2には必要に応じてconstキーワードを付けて定数扱いし、以下の4パターンについて計測を行う
 - s0、s1、s2が全て変数(変数だけ結合する)
 - s0、s1、s2が全て定数(定数だけ結合する)
 - s0とs1が変数、s2が定数(変数と定数を交互に結合する)
 - s0が変数、s1とs2が定数(最初だけ変数を結合し、後は定数を結合する)

実際に動作させると以下のようなコンソールが表示される。
![実行結果](https://qiita-image-store.s3.amazonaws.com/0/318712/e59c9536-08e3-f58d-b0b2-21418e1eda9d.png)

#計測結果
上のコードを実行し、表示された結果を以下に表にしてまとめる。
なお、数値は有効数字3桁とする。
##s0、s1、s2が全て変数(変数だけ結合)の時
0(空処理)：0.000221ms

|結合数\結合方法|str +=|Sb.Append()|
|:------------:|:------------|:------------|
|1|0.000178ms|0.000233ms|
|2|0.000357ms|0.000294ms|
|3|0.000367ms|0.000293ms|
|4|0.000585ms|0.000360ms|
|5|0.000592ms|0.000359ms|
|6|0.000566ms|0.000356ms|
|7|0.000707ms|0.000400ms|
|8|0.000633ms|0.000453ms|
|9|0.000789ms|0.000483ms|
|10|0.000946ms|0.000547ms|
|20|0.00142ms|0.000107ms|
|30|0.00181ms|0.00108ms|
|40|0.00208ms|0.00123ms|
|50|0.00274ms|0.00170ms|
|60|0.00284ms|0.00161ms|
|70|0.00313ms|0.00190ms|
|80|0.00307ms|0.00195ms|
|90|0.00319ms|0.00208ms|
|100|0.00364ms|0.00238ms|

結合数が1個の時は+演算子による結合が速かったが、それ以外ではStringBuilderの方が大体1.5～2倍処理が速かった。

##s0、s1、s2が全て定数(定数だけ結合)の時
0(空処理)：0.000221ms

|結合数\結合方法|str +=|Sb.Append()|
|:------------:|:------------|:------------|
|1|0.000198ms|0.000224ms|
|2|0.000199ms|0.000263ms|
|3|0.000190ms|0.000370ms|
|4|0.000262ms|0.000322ms|
|5|0.000242ms|0.000359ms|
|6|0.000213ms|0.000399ms|
|7|0.000167ms|0.000308ms|
|8|0.000172ms|0.000362ms|
|9|0.000137ms|0.000398ms|
|10|0.000115ms|0.000405ms|
|20|0.000138ms|0.000914ms|
|30|0.000204ms|0.00115ms|
|40|0.000197ms|0.00132ms|
|50|0.000131ms|0.00150ms|
|60|0.000159ms|0.00167ms|
|70|0.000128ms|0.00219ms|
|80|0.000150ms|0.00242ms|
|90|0.000166ms|0.00251ms|
|100|0.000149ms|0.00270ms|

<font color = "red">**結合する文字列の個数に限らず+演算子による結合の方が速かった。**</font>
最終的に+演算子がStringBuilderの20倍近い処理速度になっていた。爆速レベルだ:open_mouth:
+演算子による結合の方は文字列の個数に限らず処理時間は0.0002ms前後だった。やはりコンパイル時に右辺を纏めているようだ。
一方、StringBuilderによる結合の処理時間は両方変数の時とほぼ変わっていない。StringBuilderによる結合では結合する文字列が変数か定数かは無関係のようだ。

##s0とs1が変数、s2が定数(変数と定数を交互に結合)の時
0(空処理)：0.000215ms

|結合数\結合方法|str +=|Sb.Append()|
|:------------:|:------------|:------------|
|1|0.000196ms|0.000243ms|
|2|0.000306ms|0.000320ms|
|3|0.000342ms|0.000289ms|
|4|0.000507ms|0.000328ms|
|5|0.000719ms|0.000393ms|
|6|0.000607ms|0.000496ms|
|7|0.000843ms|0.000483ms|
|8|0.000830ms|0.000518ms|
|9|0.000907ms|0.000652ms|
|10|0.00101ms|0.000643ms|
|20|0.00131ms|0.000652ms|
|30|0.00155ms|0.000913ms|
|40|0.00184ms|0.00106ms|
|50|0.00299ms|0.00184ms|
|60|0.00350ms|0.00206ms|
|70|0.00313ms|0.00180ms|
|80|0.00309ms|0.00192ms|
|90|0.00334ms|0.00207ms|
|100|0.00369ms|0.00228ms|

s0、s1、s2が全て変数の時とほぼ同じ結果になった。
定数同士が間に入った変数に邪魔されてコンパイル時に結合されず、結果的に全て変数の時のような振る舞いをした為だと考えられる。

##s0が変数、s1とs2が定数(最初だけ変数を結合し、後は定数を結合)の時
0(空処理)：0.000220ms

|結合数\結合方法|str +=|Sb.Append()|
|:------------:|:------------|:------------|
|1|0.000149ms|0.000249ms|
|2|0.000304ms|0.000297ms|
|3|0.000299ms|0.000291ms|
|4|0.000336ms|0.000319ms|
|5|0.000324ms|0.000380ms|
|6|0.000410ms|0.000351ms|
|7|0.000361ms|0.000379ms|
|8|0.000311ms|0.000351ms|
|9|0.000272ms|0.000371ms|
|10|0.000294ms|0.000478ms|
|20|0.000453ms|0.000780ms|
|30|0.000527ms|0.00111ms|
|40|0.000487ms|0.00117ms|
|50|0.000497ms|0.00143ms|
|60|0.000593ms|0.00167ms|
|70|0.000609ms|0.00206ms|
|80|0.000673ms|0.00224ms|
|90|0.000825ms|0.00243ms|
|100|0.000760ms|0.00269ms|

StringBuilderの方は上3つと同じような結果になった。
+演算子の方も処理時間は増えてはいるが変数だけを結合する時、変数と定数を交互に結合する時に比べると増加割合がずっと少ない。結合数が8個まではStringBuilderと良い勝負をしており、それ以降はStringBuilderより処理時間が短くなっている。これらの事から次の事が言えるだろう。

- 結合する文字列に変数が混ざっていても、定数同士で結合可能ならばコンパイル時に結合し、処理時間が短くなる
- 変数+定数を行うコストがあるので、定数だけの場合よりかはどうしても処理が遅くなる(どちらかの値が大きくなればそれだけ遅くなる)

また、今回は定数同士が最も結合できるパターンで検証したにも関わらず、StringBuilderと比較した処理速度が定数の時だけの20倍から3倍程度に大幅に落ち込んでいる。(それでも十分速いが)
このことから結合する文字列に1つでも変数が混ざる=処理が大幅に遅くなるという認識で良いだろう。
定数同士が最も結合できないパターン=変数と定数が交互にある時が遅い事を考えると結合する文字列に定数と変数が混合している時、定数同士が一定以上結合可能で文字列が多い時以外はStringBuilderを使うべきだろう。

#まとめ

- **結合する文字列が変数か定数に関わらず、StringBuilderによる結合は一定の処理速度を保つ**
- **結合する文字列が`変数`だけの場合、`StringBuilder`による結合の方が+演算子による結合より1.5～2倍処理が速い**
- **結合する文字列が`定数`だけの場合、`+演算子`による結合の方がStringBuilderによる結合より最大20倍処理が速い**
- **結合する文字列が`変数と定数`が混在する場合、+演算子による結合速度は「結合する文字列が変数だけの場合の1～約6倍」で変動する**
 - 変数が1つでも混ざるだけで+演算子による結合速度は定数だけを結合する場合よりも無条件で遅くなる
 - 変数だけの場合の約6倍の処理速度(最速)の時も結合する文字列が8つまではStringBuilderと同程度の処理速度である
 - なので、定数同士を多く結合出来て結合する文字列が余程多くない限り、**`文字列の結合はStringBuilderを使った方が速くなる`**

C#で長編小説でも書かない限りは文字列結合は変数と定数の混在、それも交互に結合する形になると思うので文字列結合はやはりStringBuilderを使うべきだろう。

#おまけ：Unity環境での計測
Unity環境でも上のようなコードを作って文字列結合の速度を計測した。
結論を言うとこの記事で検証した結果とほぼ同じ結果になった。違いを言うなら結合する文字列の数を増やすと処理が遅くなり、最終的に+演算子による結合もStringBuilderによる結合も上の結果の3倍ほど時間が掛かった。

<details><summary>詳しい検証と結果は折り畳みの中にある</summary><div>
まず、計測用のコードは以下の通り。

```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
	void Awake ()
	{
		string str = "";//こいつに文字を追加する
		System.Text.StringBuilder Sb = new System.Text.StringBuilder ();//こいつに文字を追加する
		string s0 = "あたいったら最強ね！";//最初に追加する文字
		string s1 = "あたいったら最強ね！";//追加する文字
		const string s2 = "あたいったら最強ね！";//追加する文字、混合の時はこっちを定数にする
		string Result;//表示の時に使う
		int i;
		int p;//処理パターン
		const int n = 100000;//試行回数
		System.Diagnostics.Stopwatch Sw = new System.Diagnostics.Stopwatch ();//処理時間計測用ストップウォッチ
		double TotalTime = 0;

		for (p = 0; p < 39; p++)
		{
			TotalTime = 0;
			for (i = 0; i < n; i++)
			{
				str = "";//文字列とストップウォッチをリセット
				Sb.Clear ();
				Sw.Reset ();
				Sw.Start ();
				switch (p)
				{
				case 0://何もしない
					break;
				case 1://1
					str += s0;
					break;
				case 2:
					Sb.Append (s0);
					break;
				case 3://2
					str += s0 + s2;
					break;
				case 4:
					Sb.Append (s0).Append (s2);
					break;
				case 5://3
					str += s0 + s2 + s1;
					break;
				case 6:
					Sb.Append (s0).Append (s2).Append (s1);
					break;
				case 7://4
					str += s0 + s2 + s1 + s2;
					break;
				case 8:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2);
					break;
				case 9://5
					str += s0 + s2 + s1 + s2 + s1;
					break;
				case 10:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1);
					break;
				case 11://6
					str += s0 + s2 + s1 + s2 + s1 + s2;
					break;
				case 12:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 13://7
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1;
					break;
				case 14:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1);
					break;
				case 15://8
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 16:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 17://9
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1;
					break;
				case 18:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1);
					break;
				case 19://10
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 20:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 21://20
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 22:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 23://30
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 24:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 25://40
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 26:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 27://50
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 28:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 29://60
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 30:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 31://70
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 32:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 33://80
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 34:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 35://80
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 36:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				case 37://100
					str += s0 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2 + s1 + s2;
					break;
				case 38:
					Sb.Append (s0).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2).Append (s1).Append (s2);
					break;
				}
				Sw.Stop ();
				TotalTime += Sw.Elapsed.TotalMilliseconds;
			}
			//かかった時間を表示
			if (p == 0)
			{
				Result = "空";
			}
			else
			{
				if (p % 2 == 1)
				{
					Result = "str";
				}
				else
				{
					Result = "Sb";
				}
				if (p <= 20)
				{
					Result += Mathf.Ceil (p / 2f).ToString ();
				}
				else
				{
					Result += (Mathf.Ceil ((p - 18) / 2f) * 10).ToString ();
				}
			}
			//かかった時間を表示
			Debug.Log (Result + "：" + (TotalTime / n) + "ms");
		}
	}
}
```

これを適当なオブジェクトにアタッチして実行したらコンソールログがこんな感じになる。
![実行結果(Unity)](https://qiita-image-store.s3.amazonaws.com/0/318712/304701e2-db2c-e9ea-82f0-bf9e0d05c81d.png)
</div></details>