7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[小ネタ] 文字列のSwitch

Posted at

##はじめに
C#では、文字列をSwitch文に使用することが可能です。
いつもながら、気になったので中で何をしているのかちょっと調べてみました。

また、@Temarin_PITAさんの検証で、
VS2015RCだと、VS2013とのコンパイル結果に差異が有るようなので、ご留意の程・・・

##とりあえずばらしてみる

要素数が少ないとき(現状要素数がdefault含めて7個以下の時)に、下記のようなコードを書いた場合


		static string Sample(string value)
		{
			string ret;


			switch (value)
			{
				case "0":
					ret = "Zero";
					break;

				case "1":
					ret = "One";
					break;

				case "2":
					ret = "Two";
					break;
					
				case "3":
					ret = "Three";
					break;

				case "4":
					ret = "Four";
					break;

				default:
					ret = "N/A";
					break;
			}

			return ret;

		}

こいつのコンパイル結果は、以下のように、ifの連接としてコンパイルされていました。


		static string Decompile(string value)
		{
			string ret;
			if (value != null)
			{
				if (value == "0")
				{
					ret = "Zero";
					return ret;
				}
				if (value == "1")
				{
					ret = "One";
					return ret;
				}
				if (value == "2")
				{
					ret = "Two";
					return ret;
				}
				if (value == "3")
				{
					ret = "Three";
					return ret;
				}
				if (value == "4")
				{
					ret = "Four";
					return ret;
				}
			}
			ret = "N/A";
			return ret;
		}

可読性他は別として、switchのケースを増やした場合、上記をそのまま使い続ければ当然効率が線形的に悪化するのは明かです。
それでは、ケースを以下のように増やした場合、どのようになるか検証してみます。


	static string Sample(string value)
		{
			string ret;


			switch (value)
			{
				case "0":
					ret = "Zero";
					break;

				case "1":
					ret = "One";
					break;

				case "2":
					ret = "Two";
					break;
					
				case "3":
					ret = "Three";
					break;

				case "4":
					ret = "Four";
					break;

				case "5":
					ret = "Five";
					break;

				default:
					ret = "N/A";
					break;
			}

			return ret;

		}

要素数を増やした場合、CSCは以下のようにコンパイルします(但し、完全に一致はしていません)


		//便宜上ここに書いてるけど、本当は別クラスのパブリックフィールドとして存在している。
		volatile private static Dictionary<string, int> _dictionary;
		static string Decompile(string value)
		{
			string ret = null;

			if (_dictionary == null)
			{
				_dictionary = new Dictionary<string, int> {{"0", 0}, {"1", 1}, {"2", 2}, {"3", 3}, {"4", 4}, {"5", 5}};
			}

			int tmp;

			if (value!=null&&_dictionary.TryGetValue(value, out tmp))
			{
				switch (tmp)
				{
					case 0:
						ret = "Zero";
						break;

					case 1:
						ret = "One";
						break;

					case 2:
						ret = "Two";
						break;

					case 3:
						ret = "Three";
						break;

					case 4:
						ret = "Four";
						break;

					case 5:
						ret = "Five";
						break;
				}
			}
			else
			{
				ret = "N/A";
			}

			return ret;
		}

このように、ケースが増えた場合、隠しDictionaryを構築して、効率化を図っています。

##まとめ
switch文に文字列を利用した場合、数値を利用した場合に比べて実行効率はなんとなく落ちそうだな位には思っていたのですが、
実際土くらい落ちるのか検証したところ、結構興味深い結果が出てきたのでまとめてみました。

但し、先に述べたとおり、次期Visual Studio2015ではコンパイル結果が大きく変化しているので、あくまでも、現状がこのようなコトになっていると言う点はご留意ください。

また、要素数が少ない場合なぜ辞書を構築しないかは、恐らくオーバーヘッドを嫌ってのことでは無いかなと予測しています。

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?