【C#】パターンマッチング完全ガイド!9つの具体的なサンプルコード

C#でのパターンマッチングの解説の画像C#
この記事は約15分で読めます。

※本記事のコンテンツは、利用目的を問わずご活用いただけます。実務経験10000時間以上のエンジニアが監修しており、基礎知識があれば初心者にも理解していただけるように、常に解説内容のわかりやすさや記事の品質に注力しております。不具合・分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。(理解できない部分などの個別相談も無償で承っております)
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)


はじめに

C#のプログラミング言語を使ったパターンマッチングは、データの型や特徴を識別し、それに応じて異なる処理を行うための強力なツールです。

この記事では、C#でのパターンマッチングの基本から、さらに複雑な使い方までを学ぶことができます。

初心者から経験者まで、C#のパターンマッチングを理解し、実際のコードに応用するための基礎を築くことができるでしょう。

●C#のパターンマッチングとは

C#におけるパターンマッチングは、C# 7.0以降で導入された機能の一つで、特にC# 8.0以降ではさらにその機能が強化されました。

この技術は、コードの可読性を高め、複雑な条件分岐をシンプルに記述することを可能にします。

パターンマッチングを使用することで、変数の型だけでなく、その値や状態に応じて異なる処理を行うことができるようになります。

○パターンマッチングの基本概念

パターンマッチングは、あるオブジェクトが特定の型、値、あるいは構造を持つかどうかをチェックし、それに応じて異なるアクションを取るプログラミング手法です。

例えば、あるオブジェクトが特定のクラスのインスタンスであるか、特定の範囲の値を持っているかなどを判断し、それぞれのケースに対応するコードブロックを実行します。

これにより、従来のif-else文やswitch文をより柔軟に、そして読みやすく記述することが可能になります。

○C#でのパターンマッチングの特徴

C#におけるパターンマッチングは、他のプログラミング言語と比較しても特に強力で、多様なパターンがサポートされています。

例えば、型パターン(Type Patterns)、定数パターン(Constant Patterns)、変数パターン(Var Patterns)などがあり、これらを組み合わせることで、複雑な条件分岐を簡潔に表現することができます。

また、C# 8.0では、プロパティやフィールドに対するパターンマッチングも導入され、より詳細なデータ構造の分析が可能になりました。

これにより、コードの可読性と保守性が大きく向上し、より効率的なプログラミングが可能になります。

●パターンマッチングの基本的な使い方

C#でのパターンマッチングを効果的に活用するためには、まずその基本的な使い方を理解することが重要です。

パターンマッチングは、主にswitch文やif文の中で使用され、オブジェクトの型や特定の値に基づいて異なる処理を実行します。

この強力な機能を使うことで、コードの可読性が向上し、複雑な条件分岐をシンプルに表現できます。

例えば、あるオブジェクトが特定の型であるかどうかをチェックし、その型に応じて異なる処理を行いたい場合、従来はisキーワードを使って型をチェックし、その後でキャストを行う必要がありました。

しかし、パターンマッチングを使うことで、このプロセスを一つのステップで行うことができます。

○サンプルコード1:基本的なパターンマッチング

例えば、下記のサンプルコードは、オブジェクトが特定の型であるかどうかをチェックし、その型に応じて異なるメッセージを出力する簡単な例です。

object obj = "Hello World";

if (obj is string s)
{
    Console.WriteLine($"String: {s}");
}
else if (obj is int i)
{
    Console.WriteLine($"Integer: {i}");
}
else
{
    Console.WriteLine("Unknown type");
}

このコードでは、obj変数がstring型の場合、その値をsという変数に代入し、文字列に関連する処理を行います。

同様に、int型の場合は整数に関連する処理を行います。

このように、パターンマッチングを使うことで、型のチェックと変数への代入を同時に行い、コードをより簡潔に書くことができます。

○サンプルコード2:型パターンの使用

型パターンは、オブジェクトが特定の型に一致するかどうかをチェックするために使用されます。

下記のサンプルコードでは、switch文を使って複数の型に対するチェックを行います。

object obj = "Hello Pattern Matching";

switch (obj)
{
    case string s:
        Console.WriteLine($"String: {s}");
        break;
    case int i:
        Console.WriteLine($"Integer: {i}");
        break;
    default:
        Console.WriteLine("Unknown type");
        break;
}

このコードでは、objstring型またはint型のいずれかであるかをチェックし、それぞれのケースに応じた処理を実行します。

defaultケースは、いずれの型にも一致しない場合に実行されます。

このように、型パターンを使用することで、複数の型に対する条件分岐を簡潔かつ効果的に記述することが可能です。

●パターンマッチングの応用例

C#におけるパターンマッチングの応用例は多岐にわたります。

これらの応用例を理解し、適切に活用することで、より複雑なロジックを簡潔かつ効率的に記述することが可能です。

ここでは、いくつかの具体的な応用例を紹介し、それぞれに対するサンプルコードを提供します。

○サンプルコード3:複合パターンの使用

複合パターンは、異なる種類のパターンを組み合わせて使用することを指します。

下記のサンプルコードでは、型パターンとプロパティパターンを組み合わせて、より詳細な条件を指定しています。

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public static void Greet(Person person)
{
    switch (person)
    {
        case Person { Age: >= 18 } p when p.Name.StartsWith("A"):
            Console.WriteLine($"大人のAさん、こんにちは! {p.Name}");
            break;
        case Person { Age: < 18 }:
            Console.WriteLine("未成年の方、こんにちは!");
            break;
        default:
            Console.WriteLine("こんにちは、ゲストさん!");
            break;
    }
}

このコードでは、Personクラスのインスタンスが18歳以上で、名前が「A」で始まる場合に特定のメッセージを出力します。

また、18歳未満の場合とそれ以外の場合に異なるメッセージを出力するようにしています。

○サンプルコード4:プロパティパターンの応用

プロパティパターンを使うと、オブジェクトの特定のプロパティに基づいた条件分岐が可能になります。

下記のサンプルコードでは、PersonオブジェクトのAgeプロパティを使って条件分岐を行っています。

public static void CheckAge(Person person)
{
    if (person is { Age: >= 65 })
    {
        Console.WriteLine("シニア割引が適用されます。");
    }
    else
    {
        Console.WriteLine("通常料金です。");
    }
}

このコードでは、PersonオブジェクトのAgeが65歳以上である場合に「シニア割引が適用されます」というメッセージを出力し、そうでない場合には「通常料金です」と出力します。

○サンプルコード5:タプルパターンの応用

タプルパターンは、複数の値を同時にチェックする際に有効です。

下記のサンプルコードでは、タプルを用いて複数の条件を同時にチェックしています。

public static void ProcessCoordinates(int x, int y)
{
    switch (x, y)
    {
        case (0, 0):
            Console.WriteLine("原点にいます。");
            break;
        case (> 0, > 0):
            Console.WriteLine("第一象限にいます。");
            break;
        case (< 0, > 0):
            Console.WriteLine("第二象限にいます。");
            break;
        // 他の象限についても同様に処理
        default:
            Console.WriteLine("座標の位置を特定できません。");
            break;
    }
}

このコードでは、(x, y)のタプルを用いて、座標の位置に応じて異なるメッセージを出力します。

原点、第一象限、第二象限など、座標の位置に基づいたメッセージを表示することにより、複数の条件に対する応答を簡単に管理することができます。

●パターンマッチングの高度なテクニック

C#におけるパターンマッチングは、基本的な使い方だけでなく、より高度なテクニックを実現するためにも使用できます。

これらの高度なテクニックを理解し、適切に使いこなすことで、C#のプログラミングがさらに強力かつ効率的になります。

次に、パターンマッチングを応用したいくつかの高度なテクニックとそれに伴うサンプルコードを紹介します。

○サンプルコード6:パターンマッチングとLINQの組み合わせ

LINQ(Language-Integrated Query)は、C#においてデータを照会するための強力な機能です。

パターンマッチングをLINQと組み合わせることで、より複雑なデータ処理が可能になります。

下記のサンプルコードは、LINQとパターンマッチングを組み合わせて、特定の条件に一致する要素をコレクションから選択する方法を表しています。

var items = new List<object> { "Apple", 5, "Banana", 7, "Cherry" };
var fruits = items.OfType<string>().Where(fruit => fruit.StartsWith("A"));
foreach (var fruit in fruits)
{
    Console.WriteLine(fruit);
}

このコードでは、異なる型の要素を含むリストから、文字列型の要素を抽出し、その中で「A」で始まる要素だけを選択しています。

OfType<string>()メソッドとWhereメソッドを組み合わせることで、型パターンと条件パターンの両方を効率的に利用できます。

○サンプルコード7:例外処理とパターンマッチング

例外処理は、プログラムのエラーハンドリングに不可欠な部分です。

C# 7.0以降では、パターンマッチングを使って、例外処理をより柔軟に記述することができます。

下記のサンプルコードは、例外の型に基づいて異なる処理を行う方法を表しています。

try
{
    // 何らかの処理
}
catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException)
{
    Console.WriteLine("引数エラーまたは無効な操作が発生しました。");
}
catch (Exception ex)
{
    Console.WriteLine($"予期せぬ例外が発生しました: {ex.Message}");
}

このコードでは、tryブロック内の処理中に発生した例外をcatchブロックで捕捉します。

whenキーワードを使用して、特定の種類の例外(この場合はArgumentExceptionInvalidOperationException)が発生した場合のみ、特定の処理を行うようにしています。

これにより、例外の種類に応じた柔軟なエラーハンドリングが可能になります。

●パターンマッチングの最適な使用シーン

C#におけるパターンマッチングは、さまざまなシナリオでその力を発揮します。

これらの使用シーンを理解し、適切にパターンマッチングを活用することで、プログラムの可読性、保守性、効率が大幅に向上します。

ここでは、パターンマッチングを効果的に使用できるいくつかの具体的なシナリオと、それぞれに適したサンプルコードを紹介します。

○サンプルコード8:データ処理のシナリオ

データ処理では、様々な型や形式のデータを扱う必要があります。

パターンマッチングを用いることで、これらのデータを簡潔かつ効率的に処理することが可能です。

下記のサンプルコードでは、異なる型のデータを処理する方法を表しています。

var data = new List<object> { 7, "Apple", 3.14, "Orange", 100 };

foreach (var item in data)
{
    switch (item)
    {
        case int i:
            Console.WriteLine($"整数: {i}");
            break;
        case string s:
            Console.WriteLine($"文字列: {s}");
            break;
        case double d:
            Console.WriteLine($"実数: {d}");
            break;
        default:
            Console.WriteLine("未知の型");
            break;
    }
}

このコードでは、異なる型のデータを含むリストをループ処理し、各要素の型に応じた処理を行っています。

このようにパターンマッチングを使用することで、複数の型に対する処理を一つのswitch文で簡潔に記述できます。

○サンプルコード9:GUIアプリケーションでの利用

GUI(Graphical User Interface)アプリケーションでは、ユーザーからの入力やイベントに基づいて様々な処理を行います。

パターンマッチングを使用することで、これらのイベント処理をより効率的に記述できます。

下記のサンプルコードは、GUIアプリケーションにおけるパターンマッチングの使用例を表しています。

public void OnEvent(object sender, EventArgs e)
{
    if (e is MouseEventArgs mouseEvent)
    {
        Console.WriteLine($"マウスイベント: {mouseEvent.X}, {mouseEvent.Y}");
    }
    else if (e is KeyEventArgs keyEvent)
    {
        Console.WriteLine($"キーイベント: {keyEvent.KeyCode}");
    }
    // 他のイベントタイプに対する処理
}

このコードでは、イベントの型に基づいて異なる処理を行っています。

MouseEventArgsの場合はマウスイベントとして処理し、KeyEventArgsの場合はキーイベントとして処理しています。

このようにパターンマッチングを用いることで、イベントの型に応じた処理を明確かつ効率的に記述できます。

●パターンマッチングにおける注意点

C#でのパターンマッチングは非常に強力な機能ですが、その使用にはいくつかの注意点があります。

適切に活用するためには、これらのポイントを理解し、適切なケースで用いることが重要です。

ここでは、パターンマッチングを使用する際の主な注意点について詳しく解説します。

○パフォーマンスの考慮

パターンマッチングは、特に複雑な条件の場合、パフォーマンスに影響を与える可能性があります。

パターンマッチングを用いる際は、その影響を考慮し、必要に応じてパフォーマンステストを行うことが重要です。

特に、大量のデータを処理する場合や、リアルタイム性が求められるアプリケーションでは、パターンマッチングの使用によるパフォーマンスの変化を注意深く評価する必要があります。

パフォーマンスへの影響を最小限に抑えるためには、次のような点に注意することが効果的です。

  • 不要な型チェックやキャストを避ける。
  • switch文の中で、最も頻度の高いケースを先に記述する。
  • 複雑なパターンマッチングは、より単純な複数のステートメントに分割する。

○可読性とメンテナンス

パターンマッチングは、コードの可読性を向上させる一方で、複雑なパターンを使用しすぎるとコードの理解が難しくなることがあります。

可読性とメンテナンス性を保つためには、パターンマッチングを適切な範囲で使用し、コードの複雑さを適切に管理することが大切です。

可読性を高めるためには、次のようなポイントに留意すると良いでしょう。

  • パターンマッチングの条件は、なるべくシンプルに保つ。
  • パターンマッチングを使用する場所は、コードの文脈に合わせて選ぶ。
  • 複数のパターンマッチングを組み合わせる場合は、各パターンの意図をコメントで明確にする。

まとめ

本記事では、C#におけるパターンマッチングの基本から応用、さらに高度なテクニックまでを幅広く解説しました。

パターンマッチングは、プログラムの可読性を高め、複雑な条件分岐を簡潔に記述する強力なツールです。

基本的な型や値によるマッチングから、複合パターン、プロパティパターン、タプルパターンの使用例まで、様々なシナリオでの活用方法を見てきました。

この記事を通じて、読者の皆様がC#のパターンマッチングの概念を深く理解し、実際のプロジェクトでの応用が容易になることを願っています。

パターンマッチングは、コードをよりクリーンで効率的に書くための重要なキーとなるでしょう。