11 パタヌンずパタヌン マッチング

11.1 党般

パタヌンは、is挔算子 (§12.15.12)、switch_statement (§13.8.3)、およびswitch_expression (§12.12) で䜿甚しお、受信デヌタの比范察象ずなるデヌタの圢状を蚘述できたす。 デヌタの䞀郚を サブパタヌンず照合しお、パタヌンを入れ子にするこずができたす。

パタヌンは、さたざたなコンテキストの倀に察しおテストされたす。

  • switch_statementでは、switch_labelのパタヌンがswitch_statementのselector_expressionに察しおテストされたす。
  • is-pattern 挔算子を䜿甚するず、右偎のパタヌンが巊偎の匏に察しおテストされたす。
  • switch_expressionでは、switch_expressionの巊偎にある匏に察しおswitch_expression_armのパタヌンがテストされたす。
  • 入れ子になったコンテキストでは、 サブパタヌンは、 パタヌンの圢匏に応じお、プロパティ、フィヌルド、たたは他の入力倀から取埗された倀に察しおテストされたす。

パタヌンがテストされる倀を パタヌン入力倀ず呌ばれたす。

パタヌン Pは、Pで䞀臎する入力倀がQのメンバヌの 1 ぀によっお䞀臎する堎合にQ䞀連の非ガヌド パタヌンによっおサブスム化されたす。

switch ステヌトメント (§13.8.3) では、ケヌスのパタヌンが前の䞀連の非ガヌド (§13.8.3) ケヌスによっおサブスムされるず゚ラヌになりたす。 switch 匏 (§12.12) では、switch_expression_armのパタヌンが前の䞀連の無防備なswitch_expression_armパタヌンによっおサブスムされるず、゚ラヌになりたす。

可胜なすべおの入力倀に察しおセット内のパタヌンが適甚される堎合、パタヌンのセットは完党です。 䞀連のパタヌンが完党ではないこずが実装によっお怜出されるず、譊告が発行されたす。

11.2 パタヌン圢匏

11.2.1 党般

パタヌンには、次のいずれかの圢匏がありたす。

pattern
    : logical_pattern
    ;

primary_pattern
    : parenthesized_pattern
    | declaration_pattern
    | constant_pattern
    | var_pattern
    | positional_pattern
    | property_pattern
    | discard_pattern
    | type_pattern
    | relational_pattern
    | list_pattern
    | slice_pattern
    ;

parenthesized_pattern
    : '(' pattern ')'
    ;

入力をconstant_patternずpositional_patternの䞡方ずしお構文的に認識できる堎合は、constant_patternを遞択する必芁がありたす。

泚: ANTLR は、パタヌンの代わりにpositional_patternする前にconstant_patternの順序が原因で、指定された遞択を自動的に行いたす。 泚釈

'(' pattern ')'実皌働では、パタヌンをかっこで囲んで、logical_patternのいずれかを䜿甚しお組み合わせたパタヌン間の評䟡順序を適甚できたす。

䞀郚の パタヌンs では、ロヌカル倉数が宣蚀される可胜性がありたす。

各パタヌン フォヌムは、パタヌンを適甚できる入力倀の型のセットを定矩したす。 パタヌン Pはパタヌンが䞀臎する可胜性のある倀を持぀型の䞭にTがある堎合にT型に適甚できたす。 Pがに適甚できない堎合、パタヌンTがP型のパタヌン入力倀 (T) ず䞀臎するようにプログラムに衚瀺される堎合、コンパむル時゚ラヌになりたす。

䟋: 次の䟋では、 v のコンパむル時の型が TextReaderされおいるため、コンパむル時゚ラヌが生成されたす。 TextReader型の倉数は、stringず参照互換の倀を持぀こずはありたせん。

TextReader v = Console.In; // compile-time type of 'v' is 'TextReader'
if (v is string) // compile-time error
{
    // code assuming v is a string
}

ただし、 v のコンパむル時の型が objectされおいるため、次ではコンパむル時゚ラヌは生成されたせん。 object型の倉数は、stringず参照互換の倀を持぀こずができたす。

object v = Console.In;
if (v is string s)
{
    // code assuming v is a string
}

end の䟋

各パタヌン フォヌムは、パタヌンが実行時に倀 照合 倀のセットを定矩したす。

パタヌン マッチング䞭の操䜜ず副䜜甚の評䟡順序 ( Deconstructの呌び出し、プロパティ アクセス、および System.Runtime.CompilerServices.ITupleのメンバヌの呌び出し) は指定されおいたせん。

11.2.2 宣蚀パタヌン

declaration_patternは、倀が特定の型を持っおいるこずをテストし、テストが成功した堎合は、必芁に応じおその型の倉数に倀を提䟛するために䜿甚されたす。

declaration_pattern
    : type simple_designation
    ;
simple_designation
    : discard_designation
    | single_variable_designation
    ;
discard_designation
    : '_'
    ;
single_variable_designation
    : identifier
    ;

discard_designationずsingle_variable_designationの䞡方の代替手段が適甚される堎合、simple_designationを認識する堎合は、前者を遞択する必芁がありたす。

泚: ANTLR は、simple_designationの代替の順序により、指定された遞択を自動的に行いたす。 泚釈

unicode 文字゚スケヌプ シヌケンス (§6.4.2) を含む識別子を䜿甚しお参照されおいるか、Escaped_Identifier (§6.4.3) で衚されおいる堎合を陀き、declaration_patternを䜿甚しお、varずいう名前の型を持぀倀をテストするこずはできたせん。

䟋: varずいう名前の型を指定するず、is-type 構文、誀ったパタヌン、有効な declaration_pattern スペルの違いを次に瀺したす。

is varコンストラクト (指定なし) は is-type 挔算子 (§12.15.12.1) であり、オペランドのランタむム型がvarかどうかをテストしたす。

#pragma warning disable CS8981
class var { }
class C
{
    static bool M(object o) => o is var; // is-type check; o is var (the type)
}

is var yをパタヌンずしお蚘述するこずは、varずいう名前の型がスコヌプ内にある堎合のコンパむル時゚ラヌです。

#pragma warning disable CS8981
class var { }
class C
{
    static void M(object o)
    {
        if (o is var y) { } // error CS8508: 'var' refers to the in-scope type
    }
}

Escaped_Identifier (@var) たたは unicode ゚スケヌプスペル (v\u0061r) をdeclaration_patternの型ずしお䜿甚するこずは有効であり、varずいう名前の型のむンスタンスにのみ䞀臎したす。

#pragma warning disable CS8981
class var { }
class C
{
    static void M(object o)
    {
        if (o is @var y) { }    // declaration_pattern; matches instances of type 'var'
        if (o is v\u0061r z) { } // declaration_pattern; same type, unicode-escape spelling
    }
}

end の䟋

declaration_patternの型をdynamicするこずはできたせん。

型が null 蚱容倀 型 (§8.3.12) たたは null 蚱容参照型 (§8.9.3) の堎合、コンパむル時゚ラヌです。

倀のランタむム型は、is-type 挔算子 (§12.15.12.1) で指定されたのず同じ芏則を䜿甚しお、パタヌン内の型に察しおテストされたす。 テストが成功するず、その倀パタヌン照合されたす。

泚: is-type 匏 e is T ず宣蚀パタヌン e is T _ は、䞡方が有効な堎合は同等です。 泚釈

パタヌン入力倀 (§11.1) e を指定するず、 simple_designation が discard_designationで、砎棄 (§9.2.9.2) を瀺す堎合、 e の倀は䜕にもバむンドされたせん。 それ以倖の堎合、 simple_designation が single_variable_designationの堎合は、指定された識別子によっお指定された型のロヌカル倉数 (§9.2.9) が導入されたす。 そのロヌカル倉数には、パタヌンが マッチしたずきに、その倀 パタヌン入力倀の倀が割り圓おられたす。

泚: _内ののこの凊理は、_ずしお蚘述されたスタンドアロン (§11.2.7) ずは異なりたす。埌者の堎合、スコヌプ内定数たたは _ ずいう名前の型は非衚瀺になりたせん。 泚釈

型Eは、id 倉換、暗黙的たたは明瀺的な参照倉換、ボックス化倉換、ボックス化解陀倉換、たたはからぞの暗黙的たたは明瀺的な null 蚱容倀の型倉換、たたはTたたはEのいずれかがオヌプン型 (T) である堎合にE型ずT蚀われたす。 T型に名前を付ける宣蚀パタヌンは、がず互換性のあるパタヌンであるすべおの型E (E) にT。 静的な型Tがず互換性のないパタヌン入力倀 (E) ず䞀臎するために、型Tずいう宣蚀パタヌンが䜿甚されおいる堎合、コンパむル時゚ラヌです。

泚: オヌプン型のサポヌトは、構造䜓型たたはクラス型である可胜性がある型をチェックする堎合に最も圹立ち、ボックス化は避ける必芁がありたす。 泚釈

䟋: 宣蚀パタヌンは、参照型の実行時の型テストを実行するのに圹立ち、むディオムを眮き換えたす

var v = expr as Type;
if (v != null) { /* code using v */ }

少し簡朔に

if (expr is Type v) { /* code using v */ }

end の䟋

䟋: 宣蚀パタヌンは、null 蚱容型の倀をテストするために䜿甚できたす。型Nullable<T> (たたはボックス化されたT) の倀は、倀が null 以倖で T2 idT2がT堎合、たたはTの基本型たたはむンタヌフェむスの型パタヌンず䞀臎したす。 たずえば、コヌド フラグメント内

int? x = 3;
if (x is int v) { /* code using v */ }

if ステヌトメントの条件は実行時にtrueされ、倉数vはブロック内で3型の倀intを保持したす。 ブロックの埌、倉数 v はスコヌプ内にありたすが、確実には割り圓おたせん。 end の䟋

11.2.3 定数パタヌン

constant_patternは、パタヌン入力倀 (§11.1) の倀を特定の定数倀に察しおテストするために䜿甚されたす。

constant_pattern
    : constant_expression
    ;

定数パタヌンPは、Pの定数匏から型Tぞの暗黙的な倉換がある堎合、たたはTがSystem.Span<char>たたはSystem.ReadOnlySpan<char>であり、Pの定数匏が型stringであり、nullリテラルでない堎合に、型Tに適甚されたす。

定数パタヌン Pの堎合、その 倉換された倀 は

  • パタヌン入力倀の型が敎数型たたは列挙型の堎合、パタヌンの定数倀はその型に倉換されたす。然も無くば
  • パタヌン入力倀の型が敎数型たたは列挙型の null 蚱容バヌゞョンである堎合、パタヌンの定数倀は基になる型に倉換されたす。然も無くば
  • パタヌンの定数倀の倀。

パタヌン入力倀がe倉換された倀を持぀定数パタヌンPv、

  • eが敎数型たたは列挙型、たたはいずれかの null 蚱容圢匏を持ち、v が敎数型を持぀堎合、パタヌンPマッチ匏の結果がe == v堎合は倀true。それ以倖の堎合
  • e がSystem.Span<char>型たたはSystem.ReadOnlySpan<char>型で、v が定数文字列で、v に定数倀がnullでない堎合、System.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(v))がtrueを返す堎合、パタヌンは e の倀ず䞀臎P。それ以倖の堎合
  • Pがを返す堎合は倀が䞀臎したす。

䟋: 次のメ゜ッドの switch ステヌトメントでは、ケヌス ラベルに 5 ぀の定数パタヌンが䜿甚されたす。

static decimal GetGroupTicketPrice(int visitorCount)
{
    switch (visitorCount) 
    {
        case 1: return 12.0m;
        case 2: return 20.0m;
        case 3: return 27.0m;
        case 4: return 32.0m;
        case 0: return 0.0m;
        default: throw new ArgumentException(...);
    }
}

end の䟋

11.2.4 Var パタヌン

var_patternmatchesすべおの倀。 ぀たり、 var_pattern を䜿甚したパタヌン マッチング操䜜は垞に成功したす。

var_patternはすべおの型に適甚できたす。

var ずいう名前のスコヌプ内の型がある堎合、var_patternは䜿甚できたせん。

泚: @varなどの゚スケヌプされた識別子、たたはv\u0061rなどの unicode ゚スケヌプスペルは、declaration_pattern内のスコヌプ内の型に名前を付けたすが、var_patternのコンテキスト var トヌクンのスペルを指定したせん。 したがっお、@var yずv\u0061r yのパタヌンは、ランタむム型が var ずいう名前のスコヌプ内型ず互換性がある倀にのみ䞀臎するdeclaration_pattern s (§11.2.2) です。 泚釈

var_pattern
    : 'var' designation
    ;
designation
    : simple_designation
    | tuple_designation
    ;
tuple_designation
    : '(' designations? ')'
    ;
designations
    : designation (',' designation)*
    ;

パタヌン入力倀 (§11.1) e を指定するず、指定がdiscard_designation堎合は砎棄 (§9.2.9.2) を衚し、e の倀は䜕にもバむンドされたせん。 (その名前を持぀宣蚀された倉数は、その時点でスコヌプ内にある堎合がありたすが、このコンテキストではその名前付き倉数は衚瀺されたせん)。それ以倖の堎合、指定がsingle_variable_designation堎合、実行時に e の倀は、その名前の新しく導入されたロヌカル倉数 (§9.2.9) にバむンドされ、その型は e の静的型であり、パタヌン入力倀はそのロヌカル倉数に割り圓おられたす。

指定がtuple_designationの堎合、パタヌンはフォヌム デザむンの(var (§11.2.5) に盞圓したす。 )指定は、tuple_designation内で芋぀かったものです。 たずえば、パタヌン var (x, (y, z)) は (var x, (var y, var z))ず同じです。

11.2.5 䜍眮パタヌン

positional_patternは、入力倀がnullされおいないこずを確認し、そこから倀のシヌケンスを抜出し、抜出された各倀を察応するサブパタヌンず照合したす。 倀は、3 ぀の方法のいずれかで抜出されたす。入力をタプルずしお扱うか、 Deconstruct メ゜ッドを呌び出すか、 System.Runtime.CompilerServices.ITupleを䜿甚しお入力にむンデックスを付けたす。

泚: ここでの Deconstruct の䜿甚は、 §12.7 で定矩されおいる゜ヌス レベルの分解倉換ずは異なりたす。 泚釈

positional_pattern
    : type? '(' subpatterns? ')' property_subpattern? simple_designation?
    ;
subpatterns
    : subpattern (',' subpattern)*
    ;
subpattern
    : pattern
    | subpattern_name ':' pattern
    ;
subpattern_name
    : identifier
    | subpattern_name '.' identifier
    ;

入力倀がパタヌン 型(subpatterns)に䞀臎する堎合、メ゜ッドは 型 を怜玢しお Deconstruct のアクセス可胜な宣蚀を怜玢し、分解割り圓お (§12.24.3) ず同じ芏則を䜿甚しおそれらの䞭から 1 ぀を遞択するこずによっお遞択されたす。 入力をconstant_patternずpositional_patternの䞡方ずしお構文的に認識できる堎合は、constant_patternを遞択する必芁がありたす。

泚: タプル リテラルは、亀換可胜ではないいく぀かの異なる圢匏のパタヌンで照合できたす。

  • (int, int) xは、型(int, int)ずsimple_designationxを持぀declaration_patternです。
  • var (x, y) は 、tuple_designation を持぀ var_patternです。
  • (int x, int y) は positional_patternです。
  • (int, int) (x, y) は有効なパタヌンではありたせん。

泚釈

リスト内のパタヌンず䞀臎する倀を抜出するには、

  1. タプル フォヌム。 型を省略し、入力倀の静的型がタプル型 (§8.3.11) の堎合、たたは入力倀がタプル リテラル (§12.8.6) の堎合は、このケヌスが適甚されたす。 n がそのタプル型のアリティず等しくない堎合、コンパむル時゚ラヌになりたす。 実行時に、各タプル芁玠は察応する サブパタヌンず照合されたす。これらのすべおが成功した堎合、䞀臎は成功したす。 サブパタヌンに識別子がある堎合、その識別子はタプル型の察応する䜍眮にタプル芁玠の名前を付けたす。
  2. フォヌムを分解したす。 それ以倖の堎合、いずれかの 型 が存圚するか、 型 が省略され、入力倀の静的型にアクセス可胜な Deconstruct メ゜ッド (§12.7) が含たれおいる堎合は、このケヌスが適甚されたす。 型が存圚する堎合は D を型にする。それ以倖の堎合は、D を入力倀の静的な型にするこずができたす。 Deconstructメ゜ッドは、分解割り圓お (§12.24.3) ず同じオヌバヌロヌド解決芏則を䜿甚しお D から遞択されたす。out パラメヌタヌの数が n に等しいずいう远加芁件がありたす。そのようなメ゜ッドが存圚しない堎合はコンパむル時゚ラヌです。 型が存圚する堎合、入力倀の静的型が型ずパタヌン互換性がない (§11.2.2) 堎合、コンパむル時゚ラヌになりたす。実行時に入力倀が型に察しおテストされ、そのテストが倱敗した堎合、䜍眮パタヌンの䞀臎は倱敗したす。 それ以倖の堎合、入力倀は D に倉換され、遞択した Deconstruct メ゜ッドは、 out パラメヌタヌを受け取る新しい倉数で呌び出されたす。 受信した各倀は察応する サブパタヌンず照合され、これらすべおが成功した堎合は䞀臎が成功したす。 サブパタヌンに識別子がある堎合、その識別子はパラメヌタヌにDeconstructの察応する䜍眮に名前を付けたす。
  3. ITuple フォヌム。 それ以倖の堎合、 型 を省略するず、 サブパタヌン に 識別子がなく、入力倀の静的な型が object、 System.Runtime.CompilerServices.ITuple、たたは System.Runtime.CompilerServices.ITupleぞの暗黙的な参照倉換を持぀型である堎合、このケヌスが適甚されたす。 実行時に、入力倀がnullのSystem.Runtime.CompilerServices.ITuple以倖のむンスタンスであるこずがテストされたす。そのテストが倱敗した堎合、䜍眮指定パタヌンの䞀臎は倱敗したす。 それ以倖の堎合、倀の Length プロパティが読み取られ、 n ず等しくない堎合、䜍眮指定パタヌンの䞀臎は倱敗したす。 それ以倖の堎合は、 i が 1 から n の各 i に぀いお、 i − 1 で入力倀のむンデックスを䜜成した倀が i 番目の サブパタヌンず照合され、これらすべおが成功した堎合に䞀臎が成功したす。
  4. それ以倖の堎合、倧文字ず小文字は適甚されたせん。 positional_pattern はコンパむル時゚ラヌです。

実行時にサブパタヌンが䞀臎する順序は指定されおおらず、䞀臎が倱敗しおもすべおのサブパタヌンずの䞀臎が詊行されない堎合がありたす。

䟋: ここでは、匏の結果を分解し、結果の倀を察応する入れ子になったパタヌンず照合したす。

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",
};

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);
}

end の䟋

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

var numbers = new List<int> { 10, 20, 30 };
if (SumAndAverage(numbers) is (Sum: var sum, Average: var average))
{
    Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}; average is {average}");
}
else
{
    // Note: sum and average are in scope here, but not definitely assigned
    Console.WriteLine("No numbers provided to compute sum and average.");   
}

static (double Sum, double Average)? SumAndAverage(IEnumerable<int> numbers)
{
    int sum = 0;
    int count = 0;
    foreach (int number in numbers)
    {
        sum += number;
        count++;
    }
    return count == 0 ? null : (sum, sum / count);
}

生成される出力は次のずおりです。

Sum of [10 20 30] is 60; average is 20

end の䟋

11.2.6 プロパティ パタヌン

property_patternは、入力倀がnullされおいないこずを確認し、アクセス可胜なプロパティたたはフィヌルドを䜿甚しお抜出された倀ず再垰的に䞀臎したす。

property_pattern
    : type? property_subpattern simple_designation?
    ;
property_subpattern
    : '{' '}'
    | '{' subpatterns ','? '}'
    ;

property_patternのサブパタヌンにsubpattern_nameが含たれおいない堎合ぱラヌです。

型が null 蚱容倀 型 (§8.3.12) たたは null 蚱容参照型 (§8.9.3) の堎合、コンパむル時゚ラヌです。

泚: null チェック パタヌンは、単玔なプロパティ パタヌンから陀倖されたす。 文字列 s が null 以倖かどうかを確認するには、次のいずれかの圢匏を蚘述できたす。

#nullable enable
string s = "abc";
if (s is object o) ...  // o is of type object
if (s is string x1) ... // x1 is of type string
if (s is {} x2) ...     // x2 is of type string
if (s is {}) ...

x2を宣蚀する䟋は、倉数型を掚論するずいう点でif (s is var x2)に䌌おいたすが、プロパティ パタヌンでは、x2が null 以倖であるこずが保蚌されたす。 泚釈

匏 e がパタヌン型{subpatterns} に䞀臎するず、匏 e が型によっお指定された型 T ずパタヌン互換性がない (§11.2.2) 堎合、コンパむル時゚ラヌになりたす。 型が存圚しない堎合、型は e の静的型であるず芋なされたす。 サブパタヌンの巊偎に衚瀺される各subpattern_nameは、アクセス可胜な読み取り可胜なプロパティたたは T フィヌルドを指定する必芁がありたす。property_patternのsimple_designationが存圚する堎合は、T 型のパタヌン倉数を宣蚀したす。

実行時に、匏は T に察しおテストされたす。これが倱敗した堎合、プロパティ パタヌンの䞀臎は倱敗し、結果は false。 成功した堎合、各 property_subpattern フィヌルドたたはプロパティが読み取られ、その倀が察応するパタヌンず䞀臎したす。 䞀臎党䜓の結果は、これらのいずれかの結果がfalseされた堎合にのみfalseされたす。 サブパタヌンが䞀臎する順序は指定されおおらず、倱敗した䞀臎では実行時にすべおのサブパタヌンがテストされない堎合がありたす。 䞀臎が成功し、property_patternのsimple_designationがsingle_variable_designationの堎合、宣蚀された倉数には䞀臎した倀が割り圓おられたす。

property_patternは、匿名型ずのパタヌンマッチングに䜿甚できたす。

property_subpatternは、入れ子になったメンバヌを参照できたす。 このような堎合、各名前怜玢の受信偎は、property_patternの入力の皮類から始たる、前のメンバヌ T₀ の型です。 T が null 蚱容型の堎合、T₀ はその基になる型であり、それ以倖の堎合 T₀ は T ず等しくなりたす。たずえば、フォヌム { Prop1.Prop2: pattern }のパタヌンは、{ Prop1: { Prop2: pattern } }ずたったく同じです。

泚: これには、T が null 蚱容倀型たたは参照型である堎合の null チェックが含たれたす。 この null チェックは、䜿甚できる入れ子になったプロパティが T ではなく T₀のプロパティであるこずを意味したす。繰り返しメンバヌ パスが蚱可されるため、パタヌン マッチングのコンパむルでは、パタヌンの䞀般的な郚分を利甚できたす。 泚釈

䟋:

var o = ...;
if (o is string { Length: 5 } s) ...

end の䟋

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

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."),
};

生成される出力は次のずおりです。

Hello
Hi!
12345
abc

end の䟋

11.2.7 砎棄パタヌン

すべおの匏が砎棄パタヌンず䞀臎し、その結果、匏の倀が砎棄されたす。

discard_pattern
    : '_'
    ;

構文コンテキストでパタヌンが蚱可されおいる堎合、トヌクン_がアクセス可胜な定数たたは型に察するsimple_name (§12.8.4) ずしお解決される堎合、_はdiscard_patternずしお扱われたせん。 その代わりに

  • _アクセス可胜な定数に解決された堎合、_は定数匏がその定数であるconstant_pattern (§11.2.3) ずしお解釈されたす。
  • _が型に解決された堎合、is挔算子の右偎では、コンストラクト relational_expressionis _はその型に察する is-type 挔算子 (§12.15.12.1) テストずしお解釈されたす。 パタヌンを認めるその他の構文コンテキストでは、型に解決するベア _自䜓は有効なパタヌンではありたせん。ただし、_は、declaration_patternの型 (_ x など) ずしお、たたは型に明瀺的に名前を付ける他のパタヌン 圢匏ずしお衚瀺される堎合がありたす。

この芏則は、砎棄パタヌンを導入する前に、 _ を型たたは識別子ずしお定矩したコヌドずの䞋䜍互換性を維持したす。 _アクセス可胜な定数たたは型 (ロヌカル倉数、パラメヌタヌ、フィヌルド、メ゜ッドなど) 以倖に解決された堎合、ルヌルは適甚されず、_はdiscard_patternのたたです。

泚: これはvar のの芏則に䌌おいたすが、スコヌプ内定数たたは型_の堎合、_が゚ラヌを生成するのではなく、その宣蚀ぞの参照ずしお解釈される点が異なりたす。 泚釈

䞊蚘の芏則を適甚した埌も、トヌクン _がただdiscard_patternである堎合、そのdiscard_patternがフォヌムrelational_expressionパタヌンのis党䜓のパタヌンずしお、たたはswitch_labelのパタヌン党䜓ずしお衚瀺されるコンパむル時゚ラヌになりたす。 ただし、discard_patternは倖偎のパタヌンのサブパタヌンずしお衚瀺される堎合がありたす (たずえば、positional_patternたたはproperty_patternのサブパタヌンずしお)。

泚: そのような堎合は、任意の匏ず䞀臎させるために、砎棄を䜿甚したす。 泚釈

䟋:

Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday));
Console.WriteLine(GetDiscountInPercent(null));
Console.WriteLine(GetDiscountInPercent((DayOfWeek)10));

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,
};

生成される出力は次のずおりです。

5.0
0.0
0.0

ここでは、砎棄パタヌンを䜿甚しお、 null ず、 DayOfWeek 列挙䜓の察応するメンバヌを持たない敎数倀を凊理したす。 これにより、 switch 匏が䜿甚可胜なすべおの入力倀を凊理するこずが保蚌されたす。 end の䟋

䟋: _ずいう名前のスコヌプ内定数によっお、_匏内のswitch arm の解釈がどのように倉曎されるかを瀺したす。 WithoutUnderscoreでは、_アヌムはdiscard_patternであり、任意の倀ず䞀臎したす。 WithUnderscoreでは、スコヌプ内定数_により、_ arm は0にのみ䞀臎するconstant_patternずしお解釈されたす。

static string WithoutUnderscore(int n) => n switch
{
    1 => "one",
    _ => "other",
};

static string WithUnderscore(int n)
{
    const int _ = 0;
    return n switch
    {
        1 => "one",
        _ => "zero",
        var x => "other: " + x,
    };
}

end の䟋

11.2.8 型パタヌン

type_patternは、パタヌン入力倀 (§11.1) に特定の型があるこずをテストするために䜿甚されたす。

type_pattern
    : type
    ;

型Tに名前を付ける型パタヌンは、がE (E) ず互換性のあるすべおの型Tに適甚できたす。

倀のランタむム型は、is-type 挔算子 (§12.15.12.1) で指定されたのず同じ芏則を䜿甚しお型に察しおテストされたす。 テストが成功した堎合、パタヌンはその倀ず䞀臎したす。 型が null 蚱容 型 の堎合はコンパむル時゚ラヌです。 このパタヌン フォヌムは、 null 倀ず䞀臎したせん。

11.2.9 リレヌショナル パタヌン

relational_patternは、パタヌン入力倀 (§11.1) を定数倀に察しおリレヌショナルにテストするために䜿甚されたす。

relational_pattern
    : '<'  relational_expression
    | '<=' relational_expression
    | '>'  relational_expression
    | '>=' relational_expression
    ;

定数倀に評䟡するには、relational_pattern内のrelational_expressionが必芁です。

リレヌショナル パタヌンは、関係挔算子の<をサポヌトしたす。 <=、>、>=、sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、列挙型の䞡方のオペランドを䜿甚しお、このような二項関係挔算子をサポヌトするすべおの組み蟌み型にdecimal、nint、およびnuintしたす。

relational_patternは、適切な組み蟌みの二項関係挔算子が型の䞡方のオペランドで定矩されおいる堎合、たたは明瀺的な null 蚱容倉換たたはボックス化解陀倉換がTから定数匏の型に存圚する堎合に、型TにTできたす。

匏が double.NaN、 float.NaN、たたは null 定数ず評䟡された堎合、コンパむル時゚ラヌになりたす。

入力倀に、適切な組み蟌みの二項関係挔算子が定矩されおいる型がある堎合、その挔算子の評䟡はリレヌショナル パタヌンの意味ず芋なされたす。 それ以倖の堎合、明瀺的な null 蚱容倉換たたはボックス化解陀倉換を䜿甚しお、入力倀が定数匏の型に倉換されたす。 そのような倉換が存圚しない堎合、コンパむル時゚ラヌずなりたす。 倉換が倱敗した堎合、パタヌンは䞀臎しないず芋なされたす。 倉換が成功した堎合、パタヌン マッチング操䜜の結果は、倉換された入力 e «op» v 匏を評䟡した結果です。ここで、 e は倉換された入力、«op» は関係挔算子、 v は定数匏です。

䟋:

Console.WriteLine(Classify(13));
Console.WriteLine(Classify(double.NaN));
Console.WriteLine(Classify(2.4));

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

生成される出力は次のずおりです。

Too high
Unknown
Acceptable

end の䟋

11.2.10 論理パタヌン

logical_patternは、パタヌン䞀臎の結果を吊定したり、結合 (and) たたは結合 (or) を䜿甚しお耇数のパタヌン䞀臎の結果を結合したりするために䜿甚されたす。

logical_pattern
    : disjunctive_pattern
    ;

disjunctive_pattern
    : disjunctive_pattern 'or' conjunctive_pattern
    | conjunctive_pattern
    ;

conjunctive_pattern
    : conjunctive_pattern 'and' negated_pattern
    | negated_pattern
    ;

negated_pattern
    : 'not' negated_pattern
    | primary_pattern
    ;

not、 and、および or は、たずめお パタヌン挔算子ず呌ばれたす。

negated_patternは、吊定されるパタヌンが䞀臎しない堎合に䞀臎し、その逆も䞀臎したす。 conjunctive_patternでは、䞡方のパタヌンが䞀臎する必芁がありたす。 disjunctive_patternには、いずれかのパタヌンが䞀臎する必芁がありたす。 察応する蚀語挔算子、 && 、 ||ずは異なり、 and ず or はショヌトサヌキット挔算子 ではありたせん 。

これは、パタヌン倉数が not たたは or パタヌン挔算子の䞋で宣蚀されるコンパむル時゚ラヌです。

泚: not も or もパタヌン倉数に察しお明確な代入を生成できないため、これらの䜍眮で宣蚀するのぱラヌです。 泚釈

conjunctive_patternでは、2 番目のパタヌンの入力型は、の最初のパタヌンのandたれたす。 パタヌン のPは、次のように定矩されたす。

  • Pが型パタヌンの堎合、瞮小された型は型パタヌンの型です。
  • それ以倖の堎合、 P が宣蚀パタヌンの堎合、 瞮小された型 は宣蚀パタヌンの型です。
  • それ以倖の堎合、 P が明瀺的な型を提䟛する再垰パタヌンである堎合、 瞮小された型はその型 になりたす。
  • それ以倖の堎合、Pがpositional_pattern (ITuple) のの芏則を䜿甚しお照合される堎合、瞮小された型は型System.ITuple。
  • それ以倖の堎合、Pが定数が null 定数ではなく、匏が入力型ぞの定数匏倉換を持たない定数パタヌンの堎合、瞮小された型は定数の型になりたす。
  • それ以倖の堎合、Pが、定数匏が入力型ぞの定数匏倉換を持たないリレヌショナル パタヌンの堎合、瞮小された型は定数の型になりたす。
  • それ以倖の堎合、 P が or パタヌンの堎合、 このような共通型 が存圚する堎合、 瞮小された型 はサブパタヌンの瞮小型の共通型になりたす。 このため、共通型アルゎリズムでは、ID、ボックス化、および暗黙的な参照倉換のみが考慮され、 or パタヌンのシヌケンスのすべおのサブパタヌンが考慮されたす (かっこで保護されたパタヌンは無芖されたす)。
  • それ以倖の堎合、 P が and パタヌンの堎合、 瞮小された型 は右のパタヌンの 狭い型 になりたす。 たた、巊パタヌンの 狭いタむプ は、右パタヌンの 入力タむプ である。
  • それ以倖の堎合、PはPの入力型です。

泚: 文法で瀺されおいるように、 not は andよりも優先され、 orよりも優先されたす。 これは、かっこを䜿甚しお明瀺的に指定たたはオヌバヌラむドできたす。 泚釈

パタヌンがisの右偎に衚瀺される堎合、パタヌンの範囲は文法によっお決たりたす。その結果、パタヌン挔算子and、or、およびパタヌン内のnotは、パタヌンの倖偎の論理挔算子&&、||、および!よりも厳密にバむンドされたす。

䟋:

Console.WriteLine(Classify(13));
Console.WriteLine(Classify(-100));
Console.WriteLine(Classify(5.7));

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",
};

生成される出力は次のずおりです。

High
Too low
Acceptable

end の䟋

䟋:

Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19)));
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9)));
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11)));

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}."),
};

生成される出力は次のずおりです。

winter
autumn
spring

end の䟋

䟋:

object msg = "msg";
object obj = 5;
bool flag = true;

// This is parsed as: (msg is (not int) or string)
bool result = msg is not int or string;
Console.WriteLine($"msg (\"msg\"): msg is not int or string: {result}");

// This is parsed as: (obj is (int or string)) && flag
result = obj is int or string && flag;
Console.WriteLine($"obj (5), flag (true): obj is int or string && flag: {result}");

// This is parsed as: (obj is int) || ((obj is string) && flag)
result = obj is int || obj is string && flag;
Console.WriteLine($"obj (5), flag (true): obj is int || obj is string && flag: {result}");

flag = false;
// This is parsed as: (obj is (int or string)) && flag
result = obj is int or string && flag;
Console.WriteLine($"obj (5), flag (false): obj is int or string && flag: {result}");

// This is parsed as: (obj is int) || ((obj is string) && flag)
result = obj is int || obj is string && flag;
Console.WriteLine($"obj (5), flag (false): obj is int || obj is string && flag: {result}");

生成される出力は次のずおりです。

msg ("msg"): msg is not int or string: True
obj (5), flag (true): obj is int or string && flag: True
obj (5), flag (true): obj is int || obj is string && flag: True
obj (5), flag (false): obj is int or string && flag: False
obj (5), flag (false): obj is int || obj is string && flag: True

end の䟋

11.2.11 リスト パタヌン

list_patternは、リストたたは配列内の芁玠のシヌケンスず䞀臎したす。

list_pattern
    : list_pattern_clause simple_designation?
    ;

list_pattern_clause
    : '[' (pattern (',' pattern)* ','?)? ']'
    ;

list_patternは、カりント可胜な任意の型 (§18.1) およびむンデックス可胜な (§18.1) ず互換性がありたす。これには、匕数ずしおIndexを受け取るアクセス可胜なむンデクサヌ、たたは 1 ぀のint パラメヌタヌを持぀アクセス可胜なむンデクサヌがありたす。 䞡方のむンデクサヌが存圚する堎合は、前者が掚奚されたす。 (暗黙的なむンデックスのサポヌトの詳现に぀いおは、 §18.4.2 を参照しおください)。

expr is [1, 2, 3]圢匏のパタヌンは、次のコヌドず同じです。

expr.Length is 3
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Index(1, fromEnd: false)] is 2
&& expr[new Index(2, fromEnd: false)] is 3

䟋:

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 and not 7]);  // True

end の䟋

砎棄パタヌン (§11.2.7) は、任意の 1 ぀の芁玠に䞀臎したす。

䟋:

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

if (numbers is [_, var second, _])
{
    Console.WriteLine($"The second element is {second}.");
}

end の䟋

11.2.12 スラむス パタヌン

slice_patternは 0 個以䞊の芁玠を砎棄したす。 これは、 list_pattern_clause内でのみ盎接䜿甚され、その句では最倧で 1 回のみ䜿甚されたす。

slice_pattern
    : '..' pattern?
    ;

サブパタヌンのない slice_pattern は、 list_patternず互換性のある任意の型ず互換性がありたす。 サブパタヌンを持぀slice_patternは、カりント可胜な任意の型 (§18.1) およびスラむス可胜な (§18.1) ず互換性がありたす。これには、匕数ずしおRangeを受け取るアクセス可胜なむンデクサヌ、たたは 2 ぀のSlice パラメヌタヌを持぀アクセス可胜なint メ゜ッドがありたす。 䞡方が存圚する堎合は、前者が奜たしい。 (暗黙的なむンデックスのサポヌトの詳现に぀いおは、 §18.4.2 を参照しおください)。

slice_patternは適切な砎棄のように動䜜したす。぀たり、そのようなパタヌンに察するテストは行われたせん。 代わりに、他のノヌド (぀たり、長さずむンデクサヌ) にのみ圱響したす。 たずえば、フォヌム expr is [1, .. var s, 3] のパタヌンは、次のコヌドず同じです (明瀺的な Index ず Range サポヌトによっお互換性がある堎合)。

expr.Length is >= 2
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Range(new Index(1, fromEnd: false), new Index(1, fromEnd: true))] is var s
&& expr[new Index(1, fromEnd: true)] is 3

slice_patternの入力型は、基になるthis[Range]たたは Slice メ゜ッドの戻り倀の型であり、2 ぀の䟋倖がありたす。stringず配列の堎合は、それぞれstring.SubstringずRuntimeHelpers.GetSubArrayを䜿甚したす。

䟋: スラむス パタヌンは、入力シヌケンスの先頭たたは末尟でのみ芁玠を照合するために䜿甚できたす。

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

end の䟋

䟋: サブパタヌンは、スラむス パタヌン内で入れ子にするこずができたす。

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

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);
}

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

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

end の䟋