【ITニュース解説】In C#, how do I remove switch expressions?

2025年09月10日に「Dev.to」が公開したITニュース「In C#, how do I remove switch expressions?」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

C#で`switch`式を使わないコード再構築の方法を解説。ペットの習慣マッピングを例に、既存の`switch`式を`if`文やデリゲート(Strategyパターン)へリファクタリングする具体的な手順を示す。デリゲート活用が推奨される。

出典: In C#, how do I remove switch expressions? | Dev.to公開日:

ITニュース解説

プログラミングの世界では、さまざまなコードの書き方や構造があり、それぞれに長所と短所がある。今回取り上げるのは、C#言語における「switch式」と呼ばれる記述方法と、それをより良い形に改善する方法だ。switch式は特定の条件に基づいて処理を分岐させる便利な機能だが、使い方によってはコードの保守性や可読性を低下させる可能性があり、プログラマーの間でその利用について議論が交わされることがある。この記事では、switch式のメリット・デメリットを深く掘り下げるのではなく、もしコードの中からswitch式を取り除きたいと考えたときに、どのように書き換えれば良いのかを具体的な例を通して学ぶ。システムエンジニアを目指す上で、このようなコードのリファクタリング(改善)は非常に重要なスキルとなる。

まず、元のコードがどのような目的で作られているのかを理解しよう。ここでは、ペットの「習慣」を管理するシンプルなアプリケーションを例にしている。 最初に登場するのはHabitというクラスだ。クラスとは、現実世界のモノや概念をプログラム上で表現するための設計図のようなもので、このHabitクラスはペットのさまざまな習慣、例えば「おどけるのが好きか(PlayFool)」、「シャイか(Shy)」、「冷たいシャワーが好きか(LoveColdShowers)」などを、それぞれtrue(はい)かfalse(いいえ)で表すためのものだ。これらのbool型の項目を「プロパティ」と呼び、クラスの持つ情報となる。 次にPetという「enum(イーナム)」が定義されている。enumは、いくつかの決まった選択肢の中から一つを選ぶときに使う便利な型だ。ここではCat(猫)、Dog(犬)、Rabbit(ウサギ)といったペットの種類を表している。 そして、これらの情報を使って、それぞれのペットに合わせた習慣の情報を取得するためのPetsHabitクラスがある。このクラスの中にあるMapHabitsUsingSwitchというメソッドが、まさにswitch式を使っている部分だ。このメソッドは引数としてPetの型を受け取り、そのペットの種類に応じて異なるHabitオブジェクトを返す。例えば、Pet.Dogであれば「冷たいシャワーが好きではない(LoveColdShowers = false)」、「シャイではない(Shy = false)」といった習慣を設定したHabitオブジェクトを生成し、Pet.Catであれば別の習慣を設定する、といった具合だ。このswitch式は簡潔に書ける反面、もしペットの種類が増えたり、習慣の設定が複雑になったりすると、この一つのメソッドがどんどん肥大化し、理解しにくくなる可能性がある。

では、このswitch式をなくすための最初の方法を見ていこう。それは、おなじみの「if文」に置き換える方法だ。PetsHabitクラスにMapHabitsUsingIfという新しいメソッドが追加されている。このメソッドの内部を見てみると、if (pet is Pet.Dog)if (pet is Pet.Cat)というように、複数のif文が連続して書かれているのがわかる。それぞれのif文の中で、対応するペットのHabitオブジェクトを生成して返している。 このif文による置き換えは、プログラム初心者にとって最も直感的で分かりやすいかもしれない。しかし、この方法は推奨されないことが多い。なぜなら、switch式が持つ課題を解決するどころか、さらに問題を悪化させる可能性すらあるからだ。例えば、新しいペットの種類を追加するたびに、このメソッドの中に新しいif文を追加する必要がある。これにより、メソッドがどんどん長くなり、どこにどんな処理が書かれているのか見つけにくくなる(可読性の低下)。また、一つ変更を加えるたびに、全体を注意深く確認しなければならず、バグを生みやすくなる(保守性の低下)。つまり、switch式をif文の連鎖に置き換えるだけでは、コードの構造的な問題は解決しないのだ。

そこで、もっと洗練された解決策として、デリゲートとStrategyパターンを用いたリファクタリングが提案されている。これは、オンラインのプログラミングコミュニティでしばしば推奨される方法だ。 「デリゲート」とは、メソッド(処理のまとまり)を、変数と同じように扱えるようにするC#の機能だ。例えるなら、「この処理を実行してください」という指示書を、後で誰かに渡せるように封筒に入れておくようなものだ。ここでは、Func<Habit>というデリゲートが使われている。これは、「引数を何も受け取らず、Habit型の値を返すメソッド」を指す。つまり、それぞれのペットの習慣を生成するメソッドを、このデリゲートの形にして扱おうとしているわけだ。 「Strategyパターン」とは、特定の処理(ここではペットの習慣を生成する処理)を、いくつかの異なる「戦略(Strategy)」として独立したメソッドに分け、実行時にどの戦略を使うかを選択する設計パターンのことだ。 具体的には、PetsHabitクラス内にGetHabitFunctionというプライベートなメソッドが追加されている。このメソッドは、Dictionary<Pet, Func<Habit>>という特殊なデータ構造を返している。Dictionaryは「辞書」のようなもので、キー(ここではPetの種類)とそれに対応する値(ここではFunc<Habit>、つまり習慣を生成するメソッド)をペアで管理する。GetHabitFunctionの中では、Pet.Catにはthis.GetCatHabitというメソッド、Pet.Dogにはthis.GetDogHabitというメソッドがそれぞれ関連付けられている。GetCatHabitGetDogHabitといったメソッドは、それぞれのペットに特化した習慣を生成する処理だけを担っている。 そして、これらのデリゲートとDictionaryを利用して、MapHabitsUsingDelegateメソッドがペットの習慣を取得する。このメソッドでは、まずGetHabitFunctionを呼び出して、Petの種類と習慣生成メソッドの対応表(Dictionary)を取得する。次に、引数で渡されたpetの種類がDictionaryの中に存在するかどうかをTryGetValueというメソッドで確認する。もし存在すれば、そのペットに対応する習慣生成メソッド(Func<Habit>型のデリゲート)を取り出し、それを実行してHabitオブジェクトを返す。存在しなければ、無効な習慣としてValid = falseHabitオブジェクトを返す。

このデリゲートとStrategyパターンを使ったアプローチは、switch式や連続するif文に比べて、いくつかの大きな利点がある。 第一に、「単一責任の原則」が守られやすくなる。これは、一つのメソッドやクラスは、一つの責任だけを持つべきだ、というプログラミングの原則だ。GetCatHabitGetDogHabitといったメソッドは、それぞれ猫の習慣、犬の習慣を生成するという「一つの責任」だけを持っている。これに対し、元のswitch式やif文の連鎖は、すべてのペットの習慣生成ロジックを「一つのメソッド」の中に詰め込んでいた。 第二に、コードの「拡張性」と「保守性」が向上する。もし新しいペットの種類(例えばPet.Bird)を追加する必要が出た場合、MapHabitsUsingDelegateメソッド自体を変更する必要はない。単にGetBirdHabitのような新しいメソッドを作成し、GetHabitFunctionDictionary{ Pet.Bird, this.GetBirdHabit }というエントリを追加するだけで済む。既存のコードをほとんど変更せずに機能を追加できるため、変更によるバグのリスクを減らし、開発効率を高めることができる。 第三に、コードの「可読性」が向上する。各ペットの習慣に関するロジックがそれぞれのメソッドに分離されているため、特定のペットの習慣設定を確認したいときに、該当するメソッドだけを見れば良い。全体を見通す必要がなくなり、コードが理解しやすくなる。

まとめると、C#のswitch式は簡潔に書ける一方で、ロジックが複雑化・巨大化すると保守性が低下する可能性がある。それを単純なif文の連鎖に置き換えるだけでは、問題が解決しないどころか悪化することもある。しかし、デリゲートとStrategyパターンを組み合わせることで、それぞれの処理を独立したメソッドとして定義し、それらをDictionaryで管理するという、より柔軟で拡張性の高いコード構造を実現できる。システムエンジニアとして、このようなコードの改善手法を理解し、適切に使いこなすことは、読みやすく、変更に強く、バグの少ない高品質なソフトウェアを開発するために不可欠なスキルとなる。この知識を活かして、より良いコードを書き、成長していくことを期待している。