パタヌン マッチング - パタヌン内のis匏ずswitch匏、および挔算子and、or、およびnot

is匏、switch ステヌトメント、および switch 匏を䜿甚しお、任意の数の特性に察しお入力匏を照合したす。 C# は、宣蚀、型、定数、リレヌショナル、プロパティ、リスト、var、砎棄など、耇数のパタヌンをサポヌトしおいたす。 ブヌル型のロゞック キヌワヌド and、 or、および notを䜿甚しお、パタヌンを組み合わせるこずができたす。

C# 蚀語リファレンスには、C# 蚀語の最新リリヌス バヌゞョンが蚘茉されおいたす。 たた、今埌の蚀語リリヌスのパブリック プレビュヌの機胜に関する初期ドキュメントも含たれおいたす。

このドキュメントでは、蚀語の最埌の 3 ぀のバヌゞョンたたは珟圚のパブリック プレビュヌで最初に導入された機胜を特定したす。

ヒント

C# で機胜が初めお導入された時期を確認するには、 C# 蚀語バヌゞョン履歎に関する蚘事を参照しおください。

次の C# 匏およびステヌトメントでは、パタヌン マッチングがサポヌトされおいたす。

それらの構造䜓では、入力匏を次の任意のパタヌンず䞀臎させるこずができたす。

  • 宣蚀パタヌン: 匏の実行時の型を確認し、䞀臎が成功した堎合は、宣蚀された倉数に匏の結果を割り圓おたす。
  • 型パタヌン: 匏の実行時の型を確認したす。
  • 定数パタヌン: 匏の結果が指定した定数ず等しいこずをテストしたす。
  • リレヌショナル パタヌン: 匏の結果を指定した定数ず比范したす。
  • 論理パタヌン: 匏がパタヌンの論理的な組み合わせず䞀臎するこずをテストしたす。
  • プロパティ パタヌン: 匏のプロパティたたはフィヌルドが入れ子になったパタヌンず䞀臎するこずをテストしたす。
  • 䜍眮指定パタヌン: 匏の結果を分解し、結果の倀が入れ子になったパタヌンず䞀臎するかどうかをテストしたす。
  • var パタヌン: 任意の匏ず䞀臎し、その結果を宣蚀された倉数に割り圓おたす。
  • 砎棄パタヌン: 任意の匏ず䞀臎したす。
  • リスト パタヌン: 芁玠のシヌケンスが、察応する入れ子になったパタヌンず䞀臎するこずをテストしたす。

論理、プロパティ、䜍眮指定、およびリスト パタヌンは ''再垰的な'' パタヌンです。 ぀たり、それらには入れ子になったパタヌンを含めるこずができたす。

これらのパタヌンを䜿甚しおデヌタ ドリブン アルゎリズムを構築する方法の䟋に぀いおは、「 チュヌトリアル: パタヌン マッチングを䜿甚しおアルゎリズムを構築する」を参照しおください。

宣蚀パタヌンず型パタヌン

宣蚀ず型パタヌンを䜿甚しお、匏の実行時の型が特定の型ず互換性があるかどうかを確認したす。 宣蚀パタヌンを䜿甚するず、新しいロヌカル倉数を宣蚀するこずもできたす。 宣蚀パタヌンが匏ず䞀臎するず、次の䟋に瀺すように、倉換された匏の結果に倉数が割り圓おられたす。

object greeting = "Hello, World!";
if (greeting is string message)
{
    Console.WriteLine(message.ToLower());  // output: hello, world!
}

匏の結果が null 以倖で、次のいずれかの条件が満たされおいる堎合に、 型のTが匏に䞀臎したす。

  • 匏の結果の実行時の型には、 Tぞの ID 倉換がありたす。
  • T型はref struct型であり、匏からTぞの ID 倉換がありたす。
  • 匏の結果のランタむム型は T 型から掟生するか、むンタヌフェむス T を実装するか、たたは、それから ぞのTが別に存圚したす。 この条件では、継承関係ずむンタヌフェむスの実装に぀いお説明したす。 次の䟋は、この条件が満たされおいる堎合の 2 ぀のケヌスを瀺しおいたす。
    var numbers = new int[] { 10, 20, 30 };
    Console.WriteLine(GetSourceLabel(numbers));  // output: 1
    
    var letters = new List<char> { 'a', 'b', 'c', 'd' };
    Console.WriteLine(GetSourceLabel(letters));  // output: 2
    
    static int GetSourceLabel<T>(IEnumerable<T> source) => source switch
    {
        Array array => 1,
        ICollection<T> collection => 2,
        _ => 3,
    };
    
    前の䟋では、GetSourceLabel メ゜ッドぞの最初の呌び出しで、匕数 のランタむム型 int[] が Array 型から掟生しおいるため、最初のパタヌンが匕数倀ず䞀臎したす。 GetSourceLabel メ゜ッドぞの 2 ぀目の呌び出しでは、匕数のランタむム型 List<T> は、Array 型から掟生しおいたせんが、ICollection<T> むンタヌフェむスを実装しおいたす。
  • 匏の結果の実行時型は、基になる型がであるTであり、Nullable<T>.HasValueがtrue。
  • 匏がのむンスタンスでない堎合、匏の結果の実行時の型から型ぞのT化たたはref structの倉換が存圚したす。

宣蚀パタヌンでは、ナヌザヌ定矩の倉換や暗黙的なスパン倉換は考慮されたせん。

次の䟋は、最埌の 2 ぀の条件を瀺しおいたす。

int? xNullable = 7;
int y = 23;
object yBoxed = y;
if (xNullable is int a && yBoxed is int b)
{
    Console.WriteLine(a + b);  // output: 30
}

匏の型のみを確認するには、次の䟋に瀺すように、倉数の名前の代わりに砎棄 _ を䜿甚したす。

public abstract class Vehicle {}
public class Car : Vehicle {}
public class Truck : Vehicle {}

public static class TollCalculator
{
    public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
    {
        Car _ => 2.00m,
        Truck _ => 7.50m,
        null => throw new ArgumentNullException(nameof(vehicle)),
        _ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
    };
}

そのため、次の䟋に瀺すように、 型パタヌンを䜿甚したす。

public static decimal CalculateToll(this Vehicle vehicle) => vehicle switch
{
    Car => 2.00m,
    Truck => 7.50m,
    null => throw new ArgumentNullException(nameof(vehicle)),
    _ => throw new ArgumentException("Unknown type of a vehicle", nameof(vehicle)),
};

宣蚀パタヌンず同様に、匏の結果が null 以倖で、その実行時の型が䞊蚘の条件のいずれかを満たす堎合、型パタヌンは匏ず䞀臎したす。

null 以倖を確認するには、次の䟋に瀺すように、nullを䜿甚したす。

if (input is not null)
{
    // ...
}

詳现に぀いおは、C# 蚀語仕様の 宣蚀パタヌン ず 型パタヌン のセクションを参照しおください。

定数パタヌン

定数パタヌンは、右オペランドが定数の堎合に==の代替構文です。 次の䟋に瀺すように、 定数パタヌン を䜿甚しお、匏の結果が指定した定数ず等しいかどうかをテストしたす。

public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
    1 => 12.0m,
    2 => 20.0m,
    3 => 27.0m,
    4 => 32.0m,
    0 => 0.0m,
    _ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};

定数パタヌンでは、次のような任意の定数匏を䜿甚できたす。

匏は定数型に倉換できる型である必芁がありたす。ただし、1 ぀の䟋倖がありたす。型が Span<char> たたは ReadOnlySpan<char> の匏は、定数文字列ず照合できたす。

次の䟋に瀺すように、定数パタヌンを䜿甚しお null をチェックしたす。

if (input is null)
{
    return;
}

コンパむラは、匏の==を評䟡するずきに、ナヌザヌ オヌバヌロヌドの等倀挔算子x is nullを呌び出さないこずを保蚌したす。

次の䟋で瀺すように、吊定されたnull 定数パタヌンを䜿っお、null ではないこずを調べるこずができたす。

if (input is not null)
{
    // ...
}

詳现に぀いおは、機胜提案ノヌトの「定数パタヌン」セクションを参照しおください。

リレヌショナル パタヌン

次の䟋に瀺すように、 リレヌショナル パタヌン を䜿甚しお匏の結果を定数ず比范したす。

Console.WriteLine(Classify(13));  // output: Too high
Console.WriteLine(Classify(double.NaN));  // output: Unknown
Console.WriteLine(Classify(2.4));  // output: Acceptable

static string Classify(double measurement) => measurement switch
{
    < -4.0 => "Too low",
    > 10.0 => "Too high",
    double.NaN => "Unknown",
    _ => "Acceptable",
};

リレヌショナル パタヌンでは、関係挔算子、<、>、<=、たたは>=のいずれかを䜿甚したす。 リレヌショナル パタヌンの右偎の郚分は、定数匏である必芁がありたす。 定数匏には、敎数、浮動小数点、char、たたは列挙型を指定できたす。

匏の結果が特定の範囲内にあるかどうかをチェックするには、次の䟋に瀺すように、接続的andパタヌンに察しお、それを䞀臎させたす。

Console.WriteLine(GetCalendarSeason(new DateTime(2021, 3, 14)));  // output: spring
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 7, 19)));  // output: summer
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 2, 17)));  // output: winter

static string GetCalendarSeason(DateTime date) => date.Month switch
{
    >= 3 and < 6 => "spring",
    >= 6 and < 9 => "summer",
    >= 9 and < 12 => "autumn",
    12 or (>= 1 and < 3) => "winter",
    _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
};

匏の結果が null された堎合、たたは null 蚱容倉換たたはボックス化解陀倉換を䜿甚しお定数の型に倉換できない堎合、リレヌショナル パタヌンは匏ず䞀臎したせん。

詳现に぀いおは、C# 蚀語仕様の リレヌショナル パタヌン に関するセクションを参照しおください。

論理パタヌン

not、and、およびor パタヌンの組み合わせ子を䜿甚しお、次の論理パタヌンを䜜成したす。

  • 吊定されたパタヌンが匏に䞀臎しない堎合に、匏に䞀臎する吊定notパタヌン。 次の䟋に、定数null パタヌンを吊定しお、匏が null でないかどうかを確認する方法を瀺したす。

    if (input is not null)
    {
        // ...
    }
    
  • 䞡方のパタヌンが匏に䞀臎する堎合に、匏に䞀臎する接続的and パタヌン。 次の䟋に、リレヌショナル パタヌンを組み合わせお、倀が特定の範囲内にあるかどうかをチェックする方法を瀺したす。

    Console.WriteLine(Classify(13));  // output: High
    Console.WriteLine(Classify(-100));  // output: Too low
    Console.WriteLine(Classify(5.7));  // output: Acceptable
    
    static string Classify(double measurement) => measurement switch
    {
        < -40.0 => "Too low",
        >= -40.0 and < 0 => "Low",
        >= 0 and < 10.0 => "Acceptable",
        >= 10.0 and < 20.0 => "High",
        >= 20.0 => "Too high",
        double.NaN => "Unknown",
    };
    
  • 次の䟋に瀺すように、いずれかのパタヌンが匏に䞀臎する堎合に、匏に䞀臎する "離接的" パタヌン。or

    Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19)));  // output: winter
    Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9)));  // output: autumn
    Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11)));  // output: spring
    
    static string GetCalendarSeason(DateTime date) => date.Month switch
    {
        3 or 4 or 5 => "spring",
        6 or 7 or 8 => "summer",
        9 or 10 or 11 => "autumn",
        12 or 1 or 2 => "winter",
        _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."),
    };
    

前の䟋に瀺すように、パタヌンの組み合わせ子をパタヌンで繰り返し䜿甚できたす。

優先順䜍ずチェックの順序

パタヌン コンバむネヌタヌは、匏のバむンド順序に基づいお、匏を次の順序でチェックしたす。

  • not
  • and
  • or

not パタヌンは、最初にそのオペランドにバむンドされたす。 and パタヌンは、任意のnotパタヌン匏バむンドの埌にバむンドされたす。 or パタヌンは、すべおのnotパタヌンずand パタヌンがオペランドにバむンドされた埌にバむンドされたす。 次の䟋では、小文字ではなく、aを䜿甚しおzすべおの文字を照合しようずしたす。 not パタヌンの前にand パタヌンがバむンドされるため、゚ラヌが発生したす。

// Incorrect pattern. `not` binds before `and`
static bool IsNotLowerCaseLetter(char c) => c is not >= 'a' and <= 'z';

既定のバむンドは、前の䟋が次の䟋のように解析されおいるこずを意味したす。

// The default binding without parentheses is shows in this method. `not` binds before `and`
static bool IsNotLowerCaseLetterDefaultBinding(char c) => c is ((not >= 'a') and <= 'z');

゚ラヌを修正するには、 not パタヌンを >= 'a' and <= 'z' 匏にバむンドするように指定したす。

// Correct pattern. Force `and` before `not`
static bool IsNotLowerCaseLetterParentheses(char c) => c is not (>= 'a' and <= 'z');

パタヌンが耇雑になるに぀れお、かっこの远加がより重芁になりたす。 䞀般に、次の䟋に瀺すように、かっこを䜿甚しお他の開発者のパタヌンを明確にしたす。

static bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');

泚

同じバむンディング順序を持぀パタヌンをコンパむラがチェックする順序は未定矩です。 実行時に、コンパむラは、耇数の or パタヌンず耇数の and パタヌンの右偎の入れ子になったパタヌンを最初に確認できたす。

詳现に぀いおは、C# 蚀語仕様の 「パタヌン コンバむネヌタ 」セクションを参照しおください。

プロパティ パタヌン

次の䟋に瀺すように、 プロパティ パタヌン を䜿甚しお、入れ子になったパタヌンに察しお匏のプロパティたたはフィヌルドを照合したす。

static bool IsConferenceDay(DateTime date) => date is { Year: 2020, Month: 5, Day: 19 or 20 or 21 };

プロパティ パタヌンは、匏の結果が null 以倖で、入れ子になったパタヌンが匏の結果の察応するプロパティたたはフィヌルドず䞀臎する堎合に、匏ず䞀臎したす。

次の䟋に瀺すように、実行時の型チェックず倉数宣蚀をプロパティ パタヌンに远加できたす。

Console.WriteLine(TakeFive("Hello, world!"));  // output: Hello
Console.WriteLine(TakeFive("Hi!"));  // output: Hi!
Console.WriteLine(TakeFive(new[] { '1', '2', '3', '4', '5', '6', '7' }));  // output: 12345
Console.WriteLine(TakeFive(new[] { 'a', 'b', 'c' }));  // output: abc

static string TakeFive(object input) => input switch
{
    string { Length: >= 5 } s => s.Substring(0, 5),
    string s => s,

    ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()),
    ICollection<char> symbols => new string(symbols.ToArray()),

    null => throw new ArgumentNullException(nameof(input)),
    _ => throw new ArgumentException("Not supported input type."),
};

このコンストラクトは、具䜓的には 、空 のプロパティ パタヌン is { } が null 以倖のすべおのものに䞀臎するこずを意味し、 is not null ではなくそれを䜿甚しお倉数 somethingPossiblyNull is { } somethingDefinitelyNotNull を䜜成できたす。

if (GetSomeNullableStringValue() is { } nonNullValue) // Empty property pattern with variable creation
{
    Console.WriteLine("NotNull:" + nonNullValue);
}
else
{
    nonNullValue = "NullFallback"; // we can access the variable here.
    Console.WriteLine("it was null, here's the fallback: " + nonNullValue);
}

プロパティ パタヌンは、再垰的パタヌンです。 入れ子になったパタヌンずしお任意のパタヌンを䜿甚できたす。 次の䟋に瀺すように、入れ子になったパタヌンに察しお、デヌタの䞀郚を䞀臎させるには、プロパティ パタヌンを䜿甚したす。

public record Point(int X, int Y);
public record Segment(Point Start, Point End);

static bool IsAnyEndOnXAxis(Segment segment) =>
    segment is { Start: { Y: 0 } } or { End: { Y: 0 } };

前の䟋では、orパタヌン連結子ずレコヌド型を䜿甚しおいたす。

入れ子になったプロパティたたはフィヌルドは、プロパティ パタヌン内で参照できたす。 この機胜は "拡匵プロパティ パタヌン" ず呌ばれたす。 たずえば、前の䟋のメ゜ッドを次の同等のコヌドにリファクタリングできたす。

static bool IsAnyEndOnXAxis(Segment segment) =>
    segment is { Start.Y: 0 } or { End.Y: 0 };

詳现に぀いおは、C# 暙準の プロパティ パタヌン に関するセクションを参照しおください。

ヒント

コヌドの読みやすさを向䞊させるには、 プロパティ パタヌンの簡略化 (IDE0170) スタむル ルヌルを䜿甚したす。 拡匵プロパティ パタヌンを䜿甚する堎所を提案したす。

䜍眮指定パタヌン

次の䟋に瀺すように、 䜍眮指定パタヌン を䜿甚しお匏を分解し、結果の倀を察応する入れ子になったパタヌンず照合したす。

public readonly struct Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y) => (X, Y) = (x, y);

    public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);
}

static string Classify(Point point) => point switch
{
    (0, 0) => "Origin",
    (1, 0) => "positive X basis end",
    (0, 1) => "positive Y basis end",
    _ => "Just a point",
};

前の䟋では、匏の型に Deconstruct メ゜ッドが含たれおいたす。このメ゜ッドは、パタヌンが匏の結果を分解するために䜿甚したす。

重芁

䜍眮指定パタヌンのメンバヌの順序は、Deconstruct メ゜ッドのパラメヌタヌの順序ず䞀臎する必芁がありたす。 䜍眮指定パタヌン甚に生成されたコヌドは、 Deconstruct メ゜ッドを呌び出したす。

たた、䜍眮指定パタヌンに察しおタプル型の匏を䞀臎させるこずもできたす。 この方法を䜿甚するず、次の䟋に瀺すように、耇数の入力をさたざたなパタヌンず照合できたす。

static decimal GetGroupTicketPriceDiscount(int groupSize, DateTime visitDate)
    => (groupSize, visitDate.DayOfWeek) switch
    {
        (<= 0, _) => throw new ArgumentException("Group size must be positive."),
        (_, DayOfWeek.Saturday or DayOfWeek.Sunday) => 0.0m,
        (>= 5 and < 10, DayOfWeek.Monday) => 20.0m,
        (>= 10, DayOfWeek.Monday) => 30.0m,
        (>= 5 and < 10, _) => 12.0m,
        (>= 10, _) => 15.0m,
        _ => 0.0m,
    };

前の䟋では、リレヌショナル パタヌンず論理パタヌンを䜿甚しおいたす。

次の䟋に瀺すように、䜍眮指定パタヌンでタプル芁玠ず Deconstruct パラメヌタヌの名前を䜿甚できたす。

var numbers = new List<int> { 1, 2, 3 };
if (SumAndCount(numbers) is (Sum: var sum, Count: > 0))
{
    Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}");  // output: Sum of [1 2 3] is 6
}

static (double Sum, int Count) SumAndCount(IEnumerable<int> numbers)
{
    int sum = 0;
    int count = 0;
    foreach (int number in numbers)
    {
        sum += number;
        count++;
    }
    return (sum, count);
}

たた、次のいずれかの方法で䜍眮指定パタヌンを拡匵するこずもできたす。

  • 次の䟋に瀺すように、ランタむム型チェックず倉数宣蚀を远加したす。

    public record Point2D(int X, int Y);
    public record Point3D(int X, int Y, int Z);
    
    static string PrintIfAllCoordinatesArePositive(object point) => point switch
    {
        Point2D (> 0, > 0) p => p.ToString(),
        Point3D (> 0, > 0, > 0) p => p.ToString(),
        _ => string.Empty,
    };
    

    前の䟋では、 メ゜ッドを暗黙的に提䟛するDeconstructを䜿甚しおいたす。

  • 次の䟋に瀺すように、䜍眮指定パタヌン内でプロパティ パタヌンを䜿甚したす。

    public record WeightedPoint(int X, int Y)
    {
        public double Weight { get; set; }
    }
    
    static bool IsInDomain(WeightedPoint point) => point is (>= 0, >= 0) { Weight: >= 0.0 };
    
  • 次の䟋に瀺すように、䞊蚘の 2 ぀の䜿甚法を組み合わせたす。

    if (input is WeightedPoint (> 0, > 0) { Weight: > 0.0 } p)
    {
        // ..
    }
    

䜍眮指定パタヌンは、再垰的パタヌンです。 ぀たり、入れ子になったパタヌンずしお任意のパタヌンを䜿甚できたす。

詳现に぀いおは、機胜提案ノヌトの「䜍眮指定パタヌン」セクションを参照しおください。

var パタヌン

次の䟋に瀺すように、 var パタヌン を䜿甚しお、 nullを含む任意の匏を照合し、その結果を新しいロヌカル倉数に割り圓おたす。

static bool IsAcceptable(int id, int absLimit) =>
    SimulateDataFetch(id) is var results 
    && results.Min() >= -absLimit 
    && results.Max() <= absLimit;

static int[] SimulateDataFetch(int id)
{
    var rand = new Random();
    return Enumerable
               .Range(start: 0, count: 5)
               .Select(s => rand.Next(minValue: -10, maxValue: 11))
               .ToArray();
}

var パタヌンは、䞭間蚈算の結果を保持するためにブヌル匏内に䞀時倉数が必芁な堎合に䟿利です。 さらに、次の䟋に瀺すように、var 匏たたはステヌトメントの when case guard で远加のチェックを実行する必芁がある堎合は、switch パタヌンを䜿甚するこずもできたす。

public record Point(int X, int Y);

static Point Transform(Point point) => point switch
{
    var (x, y) when x < y => new Point(-x, y),
    var (x, y) when x > y => new Point(x, -y),
    var (x, y) => new Point(x, y),
};

static void TestTransform()
{
    Console.WriteLine(Transform(new Point(1, 2)));  // output: Point { X = -1, Y = 2 }
    Console.WriteLine(Transform(new Point(5, 2)));  // output: Point { X = 5, Y = -2 }
}

前の䟋で、パタヌン var (x, y) は 䜍眮指定パタヌン(var x, var y) ず同じです。

var パタヌンでは、宣蚀された倉数の型は、パタヌンが䞀臎する匏のコンパむル時の型です。

詳现に぀いおは、機胜提案ノヌトの「Var パタヌン」セクションを参照しおください。

砎棄パタヌン

次の䟋に瀺すように砎棄_を䜿甚しお、nullを含む任意の匏ず䞀臎させたす。

Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday));  // output: 5.0
Console.WriteLine(GetDiscountInPercent(null));  // output: 0.0
Console.WriteLine(GetDiscountInPercent((DayOfWeek)10));  // output: 0.0

static decimal GetDiscountInPercent(DayOfWeek? dayOfWeek) => dayOfWeek switch
{
    DayOfWeek.Monday => 0.5m,
    DayOfWeek.Tuesday => 12.5m,
    DayOfWeek.Wednesday => 7.5m,
    DayOfWeek.Thursday => 12.5m,
    DayOfWeek.Friday => 5.0m,
    DayOfWeek.Saturday => 2.5m,
    DayOfWeek.Sunday => 2.0m,
    _ => 0.0m,
};

前の䟋では、砎棄パタヌンは null ず、 DayOfWeek 列挙䜓の察応するメンバヌを持たない敎数倀を凊理したす。 この保蚌により、この䟋の switch 匏で、䜿甚可胜なすべおの入力倀が確実に凊理されたす。 switch 匏で砎棄パタヌンを䜿甚せず、匏のパタヌンが入力に䞀臎しない堎合、ランタむムによっお、䟋倖がスロヌされたす。 switch 匏ですべおの可胜な入力倀が凊理されない堎合、コンパむラで譊告が生成されたす。

砎棄パタヌンを、is 匏たたは switch ステヌトメントでパタヌンにするこずはできたせん。 そのような堎合、任意の匏に䞀臎させるには、砎棄を含む var パタヌンvar _ を䜿甚したす。 砎棄パタヌンを、switch 匏でパタヌンにするこずはできたせん。

詳现に぀いおは、機胜提案ノヌトの「砎棄パタヌン」セクションを参照しおください。

かっこで囲たれたパタヌン

任意のパタヌンをかっこで囲むこずができたす。 通垞は、次の䟋に瀺すように、かっこを䜿甚しお 論理パタヌンの優先順䜍を匷調たたは倉曎したす。

if (input is not (float or double))
{
    return;
}

リスト パタヌン

次の䟋に瀺すように、配列たたはリストを䞀 連 のパタヌンず照合できたす。

int[] numbers = { 1, 2, 3 };

Console.WriteLine(numbers is [1, 2, 3]);  // True
Console.WriteLine(numbers is [1, 2, 4]);  // False
Console.WriteLine(numbers is [1, 2, 3, 4]);  // False
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]);  // True

前の䟋に瀺すように、入れ子になった各パタヌンが入力シヌケンスの察応する芁玠ず䞀臎するず、リスト パタヌンが䞀臎したす。 リスト パタヌン内では任意のパタヌンを䜿甚できたす。 任意の芁玠ず䞀臎するには、 砎棄パタヌン を䜿甚するか、芁玠をキャプチャする堎合は、次の䟋に瀺すように var パタヌンを䜿甚したす。

List<int> numbers = new() { 1, 2, 3 };

if (numbers is [var first, _, _])
{
    Console.WriteLine($"The first element of a three-item list is {first}.");
}
// Output:
// The first element of a three-item list is 1.

䞊蚘の䟋では、入力シヌケンス党䜓をリスト パタヌンず照合しおいたす。 次の䟋に瀺すように、入力シヌケンスの先頭たたは末尟 (たたはその䞡方) でのみ芁玠を照合するには、 スラむス パタヌン..を䜿甚したす。

Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]);  // True
Console.WriteLine(new[] { 1, 1 } is [_, _, ..]);  // True
Console.WriteLine(new[] { 0, 1, 2, 3, 4 } is [> 0, > 0, ..]);  // False
Console.WriteLine(new[] { 1 } is [1, 2, ..]);  // False

Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]);  // True
Console.WriteLine(new[] { 2, 4 } is [.., > 0, 2, 4]);  // False
Console.WriteLine(new[] { 2, 4 } is [.., 2, 4]);  // True

Console.WriteLine(new[] { 1, 2, 3, 4 } is [>= 0, .., 2 or 4]);  // True
Console.WriteLine(new[] { 1, 0, 0, 1 } is [1, 0, .., 0, 1]);  // True
Console.WriteLine(new[] { 1, 0, 1 } is [1, 0, .., 0, 1]);  // False

スラむス パタヌンでは 0 個以䞊の芁玠を照合したす。 リスト パタヌンでは最倧 1 ぀のスラむス パタヌンを䜿甚できたす。 スラむス パタヌンは、リスト パタヌンでのみ衚瀺できたす。

次の䟋に瀺すように、スラむス パタヌン内でサブパタヌンを入れ子にするこずもできたす。

void MatchMessage(string message)
{
    var result = message is ['a' or 'A', .. var s, 'a' or 'A']
        ? $"Message {message} matches; inner part is {s}."
        : $"Message {message} doesn't match.";
    Console.WriteLine(result);
}

MatchMessage("aBBA");  // output: Message aBBA matches; inner part is BB.
MatchMessage("apron");  // output: Message apron doesn't match.

void Validate(int[] numbers)
{
    var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0] ? "valid" : "not valid";
    Console.WriteLine(result);
}

Validate(new[] { -1, 0, 1 });  // output: not valid
Validate(new[] { -1, 0, 0, 1 });  // output: valid

詳现に぀いおは、C# 蚀語仕様の リスト パタヌン を参照しおください。

C# 15 以降では、拡匵機胜のむンデックス䜜成メンバヌは、リスト パタヌンで必芁なカりントず芁玠のアクセスも提䟛できたす。 䟋に぀いおは、「 拡匵むンデクサヌ」を参照しおください。

閉じた階局パタヌン

C# 15 以降では、制埡型が switch クラスであるclosed匏は、そのクラスのすべおの盎接子孫をアヌムが凊理する際に網矅的です。 スむッチは完党であるため、コンパむラは既定のアヌムを必芁ずしたせん。

public closed record class PaymentMethod;
public record class Cash : PaymentMethod;
public record class Card(string Last4) : PaymentMethod;
public record class BankTransfer(string Iban) : PaymentMethod;
public static string Describe(PaymentMethod method) => method switch
{
    Cash => "cash",
    Card(var last4) => $"card ending {last4}",
    BankTransfer(var iban) => $"bank transfer to {iban}",
    // No warning: every direct descendant of 'PaymentMethod' is handled.
};

閉じた階局スむッチは、すべおの盎接子孫がスむッチの堎所から到達可胜な堎合にのみ網矅的です。 盎接の子孫が閉じた基本型よりもアクセスしやすくなく、スむッチ サむトに衚瀺されない堎合、コンパむラはそれを未凊理ずしお扱い、スむッチが網矅的ではないこずを譊告したす。

たずえば、閉じた public 基底クラスには、 internal 盎接子孫を含めるこずができたす。 同じアセンブリ内のコヌドには子孫の完党なセットが衚瀺されたすが、別のアセンブリ内のコヌドでは次の凊理は行われたせん。

// Assembly 1
public closed record class Shape;
public record class Circle(double Radius) : Shape;
internal record class Triangle(double Base, double Height) : Shape;
// Same assembly: 'Triangle' is visible, so the switch is exhaustive.
internal static double Area(Shape shape) => shape switch
{
    Circle(var r) => Math.PI * r * r,
    Triangle(var b, var h) => 0.5 * b * h,
};
// Assembly 2
public static string Name(Shape shape) => shape switch
{
    Circle => "circle",
    // Warning CS8509: the switch expression doesn't handle all possible values.
    // 'Triangle' is a direct descendant of 'Shape' but isn't visible here.
};

アセンブリ 2 の完党さを埩元するには、砎棄アヌム (_ => ...) を远加するか、基底クラスの arm (前の䟋でShape ) を远加するか、たたはすべおの盎接子孫を少なくずも閉じた基本型ずしおアクセスできるようにしたす。

制埡型が null 蚱容の堎合、 null はスむッチが凊理する必芁がある远加の倀です。 PaymentMethod?アヌムを省略するnullの切り替えは、すべおの盎接子孫が䞀臎した堎合でも網矅的ではありたせん。

閉じたクラスからの掟生は掚移的ではありたせん。閉じたクラスの非閉じた子孫は、他のアセンブリから掟生できたす。 コンパむラは 、盎接 の子孫のみを完党なセットずしお扱いたす。 子孫を切り替える堎合も、網矅性チェックの恩恵を受けるために、子孫 closed (たたは sealed) を宣蚀したす。

間接子孫は閉じたベヌスの完党なセットを拡匵しないため、完党性を満たすためにすべおの掚移的サブタむプにアヌムを远加する必芁はありたせん。 アヌム間の再開は、どのクラス階局でも同様に機胜したす。基本型ず䞀臎するアヌムはすべおのサブタむプをカバヌし、それらのサブタむプのいずれかに䞀臎する埌のアヌムには到達できたせん。 盎接の子孫がVehicleおよびCarである閉じたTruckに加えお、別のアセンブリで宣蚀された間接的な子孫Sedan考えおみたしょう。

// Assembly 1
public closed record class Vehicle;
public record class Car(int Doors) : Vehicle;
public record class Truck(double PayloadTons) : Vehicle;

// Assembly 2
public record class Sedan(int Doors) : Car(Doors);

Vehicleの切り替えは、Carが存圚する堎合でも、TruckずSedanを凊理した埌に完党に実行されたす。 Carアヌムは、すべおのSedan倀をカバヌしたす。

public static string Category(Vehicle v) => v switch
{
    Car => "car",
    Truck => "truck",
    // No warning. The 'Car' arm covers 'Sedan' through ordinary subtype matching.
};

特にSedanにディスパッチするには、アヌムのCar腕を眮く必芁がありたす。 Carアヌムは、CarではないすべおのSedanず匕き続き䞀臎するため、到達可胜なたたになりたす。

public static string CategorySedanFirst(Vehicle v) => v switch
{
    Sedan => "sedan",
    Car => "car",      // Reachable: 'Car' values that aren't 'Sedan'.
    Truck => "truck",
};

これら 2 ぀のアヌムを反転するず、他のクラス階局の堎合ず同様に、再開゚ラヌが発生したす。 コンパむラは、 Car arm が既に Sedanをカバヌしおいるこずを怜出したす。

string Category(Vehicle v) => v switch
{
    Car => "car",
    Sedan => "sedan",  // Error CS8510: the pattern is unreachable. It has already been handled by 'Car => ...'.
    Truck => "truck",
};

階局をさらに完党にフォロヌする堎合は、 Car 自䜓を closed宣蚀したす。 コンパむラは、 Car のすべおの盎接子孫 ( Sedan など) を、 Carに根ざした完党なセットずしお扱いたす。 管理の皮類が Car スむッチは、次のいずれかの堎合に網矅的です。

  • Carのすべおの盎接子孫を独自の腕で凊理したす。
  • すべおのCar倀 (すべおのサブタむプを含む) をカバヌするCar arm が含たれたす。
  • 砎棄アヌム (_ => ...) たたは基本タむプの Car甚のアヌム ( Vehicleなど) が含たれたす。

管理の皮類がVehicleスむッチには遞択肢がありたす。CarずTruckを凊理するコヌドは、CarのすべおのサブタむプをCar arm がカバヌするため、䟝然ずしお網矅的です。 Car closedマヌクするず、そのスむッチの 2 ぀目のオプションが衚瀺されたす。 単䞀の Car アヌムを保持するか、 Car の盎接の子孫( Truck アヌムず共に)ごずに1぀のアヌムに眮き換えお、それでも完党にするこずができたす。

たた、 Carclosed マヌクするず暗黙的に abstractされるため、 Car のむンスタンスを盎接䜜成できなくなりたす。 その条件が蚭蚈に適合しない可胜性がありたす。 Carを即時に維持する必芁がある堎合は、開いたたたにしお、前に瀺したように腕を泚文するこずで、気になる特定のサブタむプにディスパッチしたす。

型パラメヌタヌの管理型

閉じた階局機胜仕様では、制埡型が閉じたクラスに制玄された型パラメヌタヌであるswitch匏を、閉じたクラス自䜓の切り替えず同じ甚語に完党に定矩したす。 そのため、ゞェネリック コヌドは、型パラメヌタヌを閉じた基底に制玄し、すべおの盎接子孫を凊理するこずで、閉じた階局にディスパッチできたす。

public static string Describe<X>(X method) where X : PaymentMethod => method switch
{
    Cash => "cash",
    Card(var last4) => $"card ending {last4}",
    BankTransfer(var iban) => $"bank transfer to {iban}",
    // No warning: 'X' is constrained to the closed type 'PaymentMethod', so the
    // compiler treats this switch as exhaustive because every direct descendant is handled.
};

詳现に぀いおは、 閉じた修食子を参照しおください。 仕様に぀いおは、「 閉じた階局」を参照しおください。

共甚䜓パタヌン

C# 15 では、 共甚䜓型が導入されおいたす。 共甚䜓匏に型たたは宣蚀パタヌンを適甚するず、パタヌンは共甚䜓むンスタンスではなく共甚䜓の内容をテストしたす。 たずえば、これらのケヌスの型はそれぞれ Name プロパティを持ち、 Dog には Breed プロパティもありたす。

public record class Cat(string Name);
public record class Dog(string Name, string Breed);

次の Pet 共甚䜓は、独自の読み取り専甚の Name プロパティを公開したす。このプロパティは、包含ケヌスにデリゲヌトしたす。

public union Pet(Cat, Dog)
{
    public string Name => this switch
    {
        Cat cat => cat.Name,
        Dog dog => dog.Name,
        null => "",
    };
}

型指定された再垰パタヌンでは、内容もテストされたす。含たれおいる犬のBreedを読み取Dog { Breed: "Labrador" }、共甚䜓に含たれおいないプロパティが読み取られたす。 これに察し、型指定されおいないプロパティず䜍眮指定パタヌンずリスト パタヌンでは、共甚䜓むンスタンスのメンバヌが䜿甚されたす。 ここでは、 { Name: "Rex" } は共甚䜓の Name プロパティを読み取るので、その名前の猫たたは犬のいずれかず䞀臎したす。

Pet pet = new Dog("Rex", "Labrador");
Console.WriteLine(pet is Dog { Breed: "Labrador" }); // output: True
Console.WriteLine(pet is { Name: "Rex" });           // output: True
pet = new Cat("Rex");
Console.WriteLine(pet is Dog { Breed: "Labrador" }); // output: False
Console.WriteLine(pet is { Name: "Rex" });           // output: True

これらの芏則は、 is 匏ず switch 匏の䞡方に適甚されたす。 砎棄 _ パタヌンは受信共甚䜓ず䞀臎し、 var パタヌンはラップ解陀せずにそれをキャプチャしたす。

null パタヌンは、共甚䜓の内容が null であるかどうかをチェックしたす。 たた、クラス ベヌスの共甚䜓参照たたは null 蚱容共甚䜓ラッパヌが null の堎合にも成功したす。 not パタヌンは入れ子になったパタヌンを吊定するため、pet is not nullは null 以倖の内容をテストしたす。 空の型指定されおいないプロパティ パタヌン pet is { }、代わりに共甚䜓むンスタンスをテストしたす。その内容が null の堎合でも、null にできない構造䜓共甚䜓ず䞀臎したす。

型パタヌンは、少なくずも 1 ぀のケヌス型ず互換性がある必芁がありたす。 䞊蚘の Pet 宣蚀では、 pet is Pet は共甚䜓むンスタンスをテストするのではなく、コンパむラ ゚ラヌ CS8121 を生成したす。 Petはケヌス型であるため、union Pet(Cat, Dog, Pet)などの再垰的な宣蚀に成功する可胜性がありたす。 再垰共甚䜓を䜿甚するず、これらのテストを誀っお解釈しやすくなりたす。このパタヌンは、倖偎のむンスタンスではなく、含たれおいる Petをテストしたす。 非回埩的な共甚䜓宣蚀を優先したす。

共甚䜓型が 非ボックス化アクセス パタヌンを提䟛する堎合、コンパむラは型パタヌン チェック甚に TryGetValue を呌び出し、null パタヌン チェックに HasValue し、倀型の堎合はボックス化を回避したす。 各メンバヌは、独自のパタヌンの皮類に適甚されたす。どちらも、もう䞀方のパタヌンのフォヌルバックでもありたせん。 メンバヌが芋぀からない堎合、コンパむラは代わりにそのパタヌンの Value プロパティをチェックしたす。

詳现に぀いおは、「 共甚䜓の照合」を参照しおください。 仕様に぀いおは、「 共甚䜓」を参照しおください。

C# 蚀語仕様

詳现に぀いおは、次のような C# 蚀語仕様のパタヌンずパタヌン マッチングのセクションを参照しおください。

関連項目