条件分岐を多数書いてコードが煩雑になっていませんか。C#ではパターンマッチングによって型チェックや値の比較、プロパティ評価、構造マッチングが簡潔に記述できます。種類が多く、どれを使えば良いか迷う方のために、主要なパターンの種類を網羅して解説します。最新情報を交えて理解を深めましょう。
目次
C# パターンマッチング 種類:主要なパターンの全体像
パターンマッチングの種類を整理し、それぞれの用途や特徴を理解することが、可読性と保守性を高める鍵です。ここでは、「C# パターンマッチング 種類」というキーワードを明確に示した上で、主要なパターンを一覧形式で説明します。
型チェック型(Type Pattern)
Type Patternは、変数が特定の型であるかをチェックし、その型でキャストして新しい変数に束縛できるパターンです。nullチェックを兼ねることもあり、if文などでの冗長な変換コードを削減します。C#7.0で導入され、以降のバージョンで拡張されています。
定数パターン(Constant Pattern)
Constant Patternは、変数が特定の定数値と等しいかどうかを判定するためのパターンです。列挙型、文字列、数値、nullなどで使われます。switch式SWITCH文でよく使われ、定数条件を明確に記述できます。
関係パターン(Relational Pattern)および論理パターン(Logical Pattern)
Relational Patternでは数値等の大小比較演算子(, =)を用いて条件を設定できます。Logical Patternでは AND/OR/NOT を使って複数のパターンを組み合わせ、複雑な条件にも対応できます。複数のパターンを組み合わせて読みやすいコードが書けます。
プロパティパターン(Property Pattern)
Property Patternはオブジェクトのプロパティやフィールドが指定した値と一致するかをネストされたパターンでチェックできます。型チェックやnullチェックも含めて、複数のプロパティを一度に評価できるため、可読性が大きく向上します。
位置パターン(Positional Pattern)
Positional Patternは Deconstruct メソッドやレコード型、タプルを使って、オブジェクトを位置(順番)で分解し、それぞれに対応する値でマッチングできるパターンです。構造が明確な型で強力に働きます。
varパターンと破棄パターン(Var Pattern & Discard Pattern)
Var Pattern は入力に対して無条件にマッチし、その結果を変数に束縛します。Discard Pattern は _ を使って値を無視してマッチさせるパターンです。どちらもパターンの最後のフォールバックや不要な部分の省略に有用です。
リストパターン(List Pattern)
配列やシーケンスの要素構造をパターンでマッチさせる List Pattern により、要素の並びや数、特定の値などに応じた条件分岐が可能になります。スライスや破棄パターンを組み合わせることで柔軟性も高くなっています。
C# パターンマッチング 種類:各パターンの使い所と導入バージョン
種類を知ったら、どの C# バージョンで導入されたか、どのような状況で使うと効果的かを理解することで選び方が明確になります。最新バージョンの仕様を含めて比較します。
導入バージョンのタイムライン
最初のパターンマッチング機能は C#7.0 で型パターン、定数パターン、varパターン、破棄パターンなど基本的なものが導入されました。
C#8.0 で Property Pattern と Positional Pattern、ネストされた構造への対応が加わりました。
さらに、その後のバージョンで論理パターン(and/or/not)、リストパターン、拡張プロパティパターンなどが追加され、より表現力が向上しています。
使い所としての典型シナリオ
次のようなシナリオでそれぞれのパターンが有効です。用途に応じて使い分けることでコードがより直感的になります。
- Type Pattern:オブジェクトの型に応じた処理分岐を行いたいとき。
- Constant Pattern:列挙型や文字列、特定の値との比較を簡潔に書きたいとき。
- Relational/Logical Pattern:範囲チェックや複数条件を組み合わせた評価が必要なとき。
- Property Pattern:オブジェクトの内部状態や複数プロパティを見て分岐したいとき。
- Positional Pattern:タプルやレコードなど構造化されたデータを扱うとき。
- Var/Discard Pattern:フォールバック処理や不要な部分を無視したいとき。
- List Pattern:配列やシーケンスの形を検証したいとき。
最新の追加と拡張ポイント
最新仕様では、プロパティパターンでドット記法を使った拡張プロパティパターンが導入され、さらに List Pattern やリストスライスといったシーケンス処理に関する機能も充実しています。
また、Logical Pattern の “not” や “and/or” がより自然な言語に近い形で使えるようになり、複雑な条件をネストして書く際の可読性が大幅に向上しています。
C# パターンマッチング 種類:コード例で理解する使い分け
パターンの種類だけでは実践でどう使い分けるか分かりにくいです。ここではタイプ別にコード例とともに使い分けのポイントを紹介します。
型・定数パターンの基本例
以下は型パターンと定数パターンを使った例です。値の型を確認するとともに、その型に応じた処理を簡潔に記述できます。
例えば、ある変数 obj が文字列か整数か、それ以外かを判断したい場合:
“`csharp
switch(obj)
{
case int n:
Console.WriteLine(数字: {n});
break;
case string s:
Console.WriteLine(文字列: {s});
break;
case null:
Console.WriteLine(ヌルです);
break;
default:
Console.WriteLine(未知の型です);
}
“`
このように複数の型と定数を一つの switch 文または switch 式で整理できます。コードの重複やキャストの明示的記述が減り、保守性も上がります。
関係・論理パターンで条件の範囲を表現
数値の範囲チェックや複数条件を組み合わせるとき、Relational Pattern と Logical Pattern が威力を発揮します。以下は点数によって判定を返す例:
“`csharp
string Grade(int score) => score switch
{
>= 90 => “A評価”,
>= 80 and “B評価”,
>= 70 and “C評価”,
“D評価”,
};
“`
このように AND 条件や OR 条件を使えば、if-else よりも読みやすくなり、網羅性の確認もしやすくなります。
プロパティ・位置・リストパターンを使った構造マッチング
データ構造がネストしていたり、タプルやレコードを使っている場合は、プロパティパターンや位置パターン、あるいはリストパターンを活用すると強力です。
例として、注文オブジェクト Order に Items や Cost プロパティがあり、それに加えてレコードとして Deconstruct が定義されている場合:
“`csharp
decimal CalculateDiscount(Order order) => order switch
{
{ Items: >10, Cost: >1000m } => 0.10m,
( >5, >500m ) => 0.05m,
{ Cost: >250m } => 0.02m,
null => throw new ArgumentNullException(),
_ => 0m,
};
“`
- プロパティパターンで複数プロパティを同時にチェック
- 位置パターンで Deconstruct を利用し順番でマッチ
- null 判定やフォールバックを discard パターンで処理
C# パターンマッチング 種類:パフォーマンスと注意点
パターンマッチングは便利ですが使い方を誤ると読みにくくなったり、意図しない不具合を招くことがあります。パフォーマンスやコンパイル警告、型安全性など注意すべきポイントを整理します。
網羅性チェックとデフォルトパターンの重要性
switch 式ではすべての入力パターンをカバーする必要があります。漏れがあるとコンパイル時に警告が出るか、実行時例外につながることがあります。最後に必ず discard パターン(_)を用いたフォールバックを設けることが望まれます。
型関係と Deconstruct の順序の注意
位置パターンでは Deconstruct メソッドで宣言された out 引数の順序に一致させる必要があります。順序が異なっていると意図した結果が得られないことがあります。型パターン、プロパティパターン、位置パターンを混合するときにはこの点に注意が必要です。
パターンが複雑になった場合の可読性と保守性
多数のネストや複数の論理結合を含むパターンは便利ですが、過剰に使うと可読性が下がります。条件が複雑な場合は部分的にメソッドに切り出したり、コメントを入れたりすることが有効です。また、パターンマッチングが導入されていない古いフレームワークでは非対応の可能性があるので対象環境を確認しておきましょう。
ほかの言語と比較:C# パターンマッチング 種類の特徴対比
同様の機能を他の言語で使った経験がある場合、どこが違うかがわかると理解が深まります。ここでは代表的言語との比較で C# の特徴を浮き彫りにします。
C# と F# や Scala の比較
関数型言語である F# や Scala は強力なパターンマッチング機能を持っています。特に代数的データ型や列挙型の分解、一致性(exhaustiveness)の警告が厳密です。C# は最近それらの特徴を取り入れつつありますが、完全に同じではありません。ユニオン型など一部の言語機能は限定的で、シンタックスの簡潔さや型安全性で差が出ます。
可読性・実用性の観点での比較
if-else に比べて switch 式やポジショナル/プロパティパターンは読みやすくなります。複雑なネストを回避でき、処理の意図が把握しやすくなります。一方、慣れていないと初見ではどのパターンが使われているか把握しにくい場合もありますので、チーム内でコーディング規約を設けて統一することが推奨されます。
まとめ
「C# パターンマッチング 種類」に関する知識として、型パターン、定数パターン、関係や論理パターン、プロパティ・位置・リストパターン、var/破棄パターンなど主要な種類を押さえることで、条件分岐を大幅にシンプルにできます。
コード例を踏まえることで、どのパターンを使うかの判断もしやすくなります。パフォーマンスや可読性に配慮し、適切に使い分けることでコードの質が高まります。
最新仕様では表現力がさらに向上しており、複雑な条件を扱う際にも大きな助けとなります。ぜひこの記事を参考に、実際のプロジェクトで活用してみてください。
コメント