C#におけるプログラミングの進化は、開発者がより簡潔で読みやすいコードを書けるようにするための歴史でもあります。
特にC# 9.0で導入された「関係パターン(Relational Patterns)」は、従来の冗長な条件分岐を劇的に改善しました。
数値の範囲判定や複雑な状態管理を行う際、これまでは複数の比較演算子を論理演算子で繋ぐ必要がありましたが、現在のC#では直感的かつ宣言的な記述が可能です。
本記事では、関係パターンを用いた範囲指定の基本から、switch文やif文での具体的な活用例、さらには論理パターンとの組み合わせまで、最新のベストプラクティスを詳しく解説します。
関係パターンによる範囲指定の基本
C#の関係パターンとは、比較演算子(<, >, <=, >=)を使用して値を判定するパターンマッチング機能の一つです。
これまでのC#では、変数を何度も記述しなければならなかった範囲チェックが、パターンとして記述できるようになりました。

従来の記述方式との違い
従来のC#では、ある変数が特定の範囲内にあるかどうかを判定する場合、論理演算子の&&(AND)を使用して、変数名を繰り返す必要がありました。
例えば、xが0以上100以下であるかを判定するには、x >= 0 && x <= 100と記述します。
これに対し、関係パターンでは変数の記述を最小限に抑え、条件そのものにフォーカスした記述が可能です。
これにより、コードの意図が明確になり、タイポによるバグ(例えば、2回目の変数名を間違えるなど)を防ぐことができます。
利用可能な比較演算子
関係パターンで使用できるのは、以下の4種類の比較演算子です。
これらは、定数やリテラルと比較する際に使用されます。
| 演算子 | 意味 | 例 |
|---|---|---|
< | 未満 | is < 10 |
<= | 以下 | is <= 10 |
> | より大きい | is > 0 |
>= | 以上 | is >= 0 |
これらの演算子を単独で使用することも可能ですが、論理パターン(and, or, not)と組み合わせることで、真価を発揮します。
switch式での範囲指定と活用例
関係パターンが最も頻繁に、そして効果的に利用される場所の一つがswitch式です。
従来のswitch文では困難だった範囲指定が、非常にスマートに記述できるようになりました。

数値範囲による多分岐処理
以下のサンプルプログラムは、テストの点数に応じて成績を判定する処理をswitch式で実装したものです。
using System;
class Program
{
static void Main()
{
int[] scores = { 95, 82, 70, 50, 105, -5 };
foreach (var score in scores)
{
// switch式と関係パターンを組み合わせた成績判定
string grade = score switch
{
>= 90 and <= 100 => "秀 (Excellent)",
>= 80 and < 90 => "優 (Very Good)",
>= 70 and < 80 => "良 (Good)",
>= 60 and < 70 => "可 (Average)",
>= 0 and < 60 => "不可 (Fail)",
_ => "無効な点数です" // デフォルトケース
};
Console.WriteLine($"点数: {score, 3} -> 判定: {grade}");
}
}
}
点数: 95 -> 判定: 秀 (Excellent)
点数: 82 -> 判定: 優 (Very Good)
点数: 70 -> 判定: 良 (Good)
点数: 50 -> 判定: 不可 (Fail)
点数: 105 -> 判定: 無効な点数です
点数: -5 -> 判定: 無効な点数です
switch式における順序の重要性
switch式は、上から順番に評価されるという性質を持っています。
そのため、範囲が重なるような指定をする場合は、より具体的な条件を上に記述する必要があります。
しかし、関係パターンでandを用いた厳密な範囲指定を行うことで、順序に依存しすぎない、堅牢なコードを構築することが可能になります。
上記の例では、>= 80 and < 90のように上限と下限を明示しているため、どの順番に書いてもロジックが壊れにくいというメリットがあります。
これは保守性の観点から非常に優れた書き方と言えます。
if文とis演算子による範囲指定
関係パターンはswitch式だけでなく、if文の条件式の中でもis演算子と共に使用できます。
これにより、従来の複雑なif条件をすっきりと整理できます。

論理パターン(and, or, not)との組み合わせ
is演算子を使用した範囲指定では、and(論理積)、or(論理和)、not(論理否定)の3つの論理パターンを組み合わせることができます。
using System;
class Program
{
static void Main()
{
CheckTemperature(25);
CheckTemperature(35);
CheckTemperature(-5);
}
static void CheckTemperature(double temp)
{
// if文とis演算子、関係パターンの組み合わせ
if (temp is >= 10 and <= 30)
{
Console.WriteLine($"{temp}度: 快適な気温です。");
}
else if (temp is < 10 or > 30)
{
// 10度未満、または30度より大きい場合
Console.WriteLine($"{temp}度: 対策が必要です。");
}
// notパターンを使用した例
if (temp is not (>= 0 and <= 40))
{
Console.WriteLine($"{temp}度: 異常な気温です!");
}
}
}
25度: 快適な気温です。
35度: 対策が必要です。
-5度: 対策が必要です。
-5度: 異常な気温です!
括弧を使用した優先順位の制御
論理パターンを複雑に組み合わせる場合、通常の数式や論理式と同様に()を使用して優先順位を明示できます。
例えば、is (>= 0 and <= 10) or (>= 90 and <= 100)のように記述することで、「極端に低い値か、極端に高い値か」といった判定を1行で分かりやすく表現できます。
この書き方は、「何を確認したいのか」というビジネスロジックが自然言語に近い形で表現されるため、後からコードを読み返した際の理解スピードを飛躍的に向上させます。
プロパティパターンとの高度な組み合わせ
関係パターンの真価は、単一の変数だけでなく、オブジェクトのプロパティに対しても適用できる点にあります。
これを「プロパティパターン」と呼びます。

オブジェクトの状態を範囲で判定する
例えば、顧客クラスのプロパティに基づいて割引率を決定するようなシーンで、関係パターンは非常に強力です。
using System;
public record Customer(string Name, int Age, int MembershipDays);
class Program
{
static void Main()
{
var c1 = new Customer("田中", 25, 500);
var c2 = new Customer("佐藤", 15, 100);
var c3 = new Customer("鈴木", 70, 1000);
Console.WriteLine($"{c1.Name}: {CalculateDiscount(c1)}%");
Console.WriteLine($"{c2.Name}: {CalculateDiscount(c2)}%");
Console.WriteLine($"{c3.Name}: {CalculateDiscount(c3)}%");
}
static int CalculateDiscount(Customer customer) => customer switch
{
// 年齢が65以上、または会員日数が365日より大きい場合に15%割引
{ Age: >= 65 } or { MembershipDays: > 365 } => 15,
// 年齢が18未満の場合に10%割引
{ Age: < 18 } => 10,
// それ以外は0%
_ => 0
};
}
田中: 15%
佐藤: 10%
鈴木: 15%
この例では、オブジェクトのプロパティを直接参照しながら、その値に対して関係パターンを適用しています。
従来のコードであれば、customer.Age >= 65 || customer.MembershipDays > 365と書く必要がありましたが、パターンマッチングを使用することで、「データ構造」と「条件」をセットで宣言的に記述できています。
範囲指定パターンを使用する際の注意点
非常に便利な関係パターンですが、使用する上でいくつか意識しておくべきポイントがあります。
浮動小数点数の比較
double型やfloat型の値を比較する場合、浮動小数点特有の精度誤差に注意が必要です。
関係パターン自体は正確に動作しますが、計算過程で生じた微小な誤差により、is 1.0のような厳密な一致判定が期待通りにならないことがあります。
範囲指定(>=など)を用いる場合は比較的安全ですが、境界値の扱いには常に慎重であるべきです。
Null許容型との親和性
関係パターンは、対象がnullである場合にはマッチしません。
例えば、int? x = null;の場合、x is > 0は偽となります。
これにより、別途nullチェックを記述しなくても、実行時に例外が発生することを防げるという隠れたメリットがあります。
パターンの網羅性 (Exhaustiveness)
switch式で関係パターンを使用する場合、コンパイラはすべての可能性がカバーされているかをチェックします。
数値範囲を指定する場合、すべての数値を網羅することは難しいため、通常は最後に_(破棄パターン)を記述して、どの条件にも当てはまらない場合の処理を定義する必要があります。
これを忘れると、実行時にマッチするパターンがない場合に例外がスローされる可能性があります。
まとめ
C#の関係パターンを用いた範囲指定は、従来の冗長な比較演算の繰り返しを排除し、可読性と保守性の高いコードを実現するための必須テクニックです。
特にswitch式との組み合わせは、複雑なビジネスルールを簡潔なマッピングとして記述することを可能にします。
本記事で紹介した内容を整理すると以下の通りです。
- 関係パターンは、比較演算子をパターンとして扱う機能である。
andやorと組み合わせることで、直感的な範囲指定が可能になる。switch式で使用すると、多分岐の範囲判定をスマートに記述できる。if (variable is ...)の形式で、従来の条件式をより自然言語に近い形で表現できる。- プロパティパターンと組み合わせることで、複雑なオブジェクトの状態判定にも応用できる。
最新のC#機能を積極的に取り入れることで、コードの意図が伝わりやすくなり、チーム開発におけるレビューの負担軽減やバグの抑制にも繋がります。
ぜひ、日々のコーディングに関係パターンを取り入れてみてください。
