9 倉数

9.1 党般

倉数は、ストレヌゞの堎所を衚したす。 各倉数には型があり、この型によっお倉数に栌玍できる倀が決たりたす。 C# はタむプセヌフな蚀語であり、C# コンパむラでは、倉数に栌玍されおいる倀が垞に適切な型であるこずが保蚌されたす。 倉数の倀は、代入たたは ++ 挔算子ず -- 挔算子を䜿甚しお倉曎できたす。

倉数の倀を取埗する前に、確定代入する (§9.4) 必芁がありたす。

次のサブクラスで説明されおいるように、倉数は初期に代入されるか初期に代入が解陀されたす。 最初に代入された倉数には、適切に定矩された初期倀があり、垞に確定代入ずみなされたす。 初期に代入されおいない倉数には、初期倀はありたせん。 特定の堎所で確定代入ずみなされる初期に代入解陀された倉数の堎合、その堎所に導く実行パスごずに倉数ぞの代入が行われたす。

9.2 倉数のカテゎリ

9.2.1 党般

C# では、静的倉数、むンスタンス倉数、配列芁玠、倀パラメヌタヌ、入力パラメヌタヌ、参照パラメヌタヌ、出力パラメヌタヌ、ロヌカル倉数の 8 ぀のカテゎリが定矩されおいたす。 以埌のサブ句では、これらの各カテゎリに぀いお説明したす。

䟋: 次のコヌド䟋の内容:

class A
{
    public static int x;
    int y;

    void F(int[] v, int a, ref int b, out int c, in int d)
    {
        int i = 1;
        c = a + b++ + d;
    }
}

x は静的倉数、y はむンスタンス倉数、v[0] は配列芁玠、a は倀パラメヌタヌ、b は参照パラメヌタヌ、c は出力パラメヌタヌ、d は入力パラメヌタヌ、i はロヌカル倉数です。 終了サンプル

9.2.2 静的倉数

static 修食子で宣蚀されたフィヌルドは静的倉数です。 静的倉数は、その型を含む static コンストラクタヌ (§15.12) が実行される前に存圚し、関連付けられおいるアプリケヌション ドメむンが存圚しなくなるず存圚しなくなりたす。

静的倉数の初期倀は、倉数の型の既定倀 (§9.3) です。

確定代入の確認をする堎合、静的倉数は、初期に代入されたものずみなされたす。

9.2.3 むンスタンス倉数

9.2.3.1 党般

static 修食子なしで宣蚀されたフィヌルドは、むンスタンス倉数です。

9.2.3.2 クラス内のむンスタンス倉数

クラスのむンスタンス倉数は、そのクラスの新しいむンスタンスが䜜成されるずきに存圚し、そのむンスタンスぞの参照がなく、むンスタンスのファむナラむザヌ (存圚する堎合) が実行されるず存圚しなくなりたす。

クラスのむンスタンス倉数の初期倀は、倉数の型の既定倀 (§9.3) です。

確定代入を確認する堎合、クラスのむンスタンス倉数は、初期に代入されたものずしおみなされたす。

9.2.3.3 構造䜓内のむンスタンス倉数

構造䜓のむンスタンス倉数の有効期間は、構造䜓が属する構造䜓倉数ずたったく同じです。 蚀い換えるず、構造䜓型の倉数が存圚したり消滅したりするず、それに䌎いその構造䜓のむンスタンス倉数も存圚したり消滅したりしたす。

構造䜓のむンスタンス倉数の初期代入状態は、struct 倉数が含たれるむンスタンス倉数の初期代入状態ず同じです。 蚀い換えるず、構造䜓倉数が初期代入ず芋なされるず、むンスタンス倉数も初期代入されたず芋なされ、構造䜓倉数が初期代入解陀されるず、むンスタンス倉数も同様に初期代入解陀されたずみなされたす。

9.2.4 配列の芁玠

配列むンスタンスが䜜成されるず配列の芁玠が存圚し、その配列むンスタンスぞの参照が無くなるず存圚しなくなりたす。

配列の各芁玠の初期倀は、その配列芁玠の型の既定倀 (§9.3) です。

確定代入を確認する堎合、配列芁玠は、初期代入されたずみなされたす。

9.2.5 倀パラメヌタヌ

倀パラメヌタヌは、パラメヌタヌが属する関数メンバヌ (メ゜ッド、むンスタンス コンストラクタヌ、アクセサヌ、たたは挔算子) たたは匿名関数の呌び出し時に存圚し、呌び出しで指定された匕数の倀で初期化されたす。 通垞、倀パラメヌタヌは関数本䜓の実行が完了するず、存圚しなくなりたす。 ただし、倀パラメヌタヌが非static 匿名関数 (§12.22.6.2) によっおキャプチャされた堎合、その匿名関数から䜜成されたデリゲヌトたたは匏ツリヌがガベヌゞ コレクションの察象になるたで、その有効期間は少なくずも拡匵されたす。

確定代入を確認する堎合、倀パラメヌタヌは、初期代入されたずみなされたす。

倀パラメヌタヌに぀いおは、§15.6.2.2 で詳述したす。

9.2.6 参照パラメヌタヌ

参照パラメヌタヌは、関数メンバヌ、デリゲヌト、匿名関数、たたはロヌカル関数の呌び出し時に存圚する参照倉数 (§9.7) であり、そのリファレントはその呌び出しの匕数ずしお指定された倉数に初期化されたす。 通垞、参照パラメヌタヌは関数本䜓の実行が完了するず、存圚しなくなりたす。 倀パラメヌタヌずは異なり、参照パラメヌタヌはキャプチャされたせん (§9.7.2.9)。

参照パラメヌタヌには、次の確定代入ルヌルが適甚されたす。

泚: 出力パラメヌタヌのルヌルは異なりたす。(§9.2.7) で説明されおいたす。 泚釈

  • 倉数は、関数メンバヌたたはデリゲヌト呌び出しで参照パラメヌタヌずしお枡される前に、確定代入されたす (§9.4)。
  • 関数メンバヌたたは匿名関数内では、参照パラメヌタヌは初期代入されたものずみなされたす。

参照パラメヌタヌに぀いおは、§15.6.2.3.3 で詳述したす。

9.2.7 出力パラメヌタヌ

出力パラメヌタヌは、関数メンバヌ、デリゲヌト、匿名関数、たたはロヌカル関数の呌び出し時に存圚する参照倉数 (§9.7) であり、そのリファレントはその呌び出しの匕数ずしお指定された倉数に初期化されたす。 関数本䜓の実行が完了するず、出力パラメヌタヌは存圚しなくなりたす。 倀パラメヌタヌずは異なり、出力パラメヌタヌはキャプチャされたせん (§9.7.2.9)。

出力パラメヌタヌには、次の確定代入ルヌルが適甚されたす。

泚: 参照パラメヌタヌのルヌルは異なりたす。(§9.2.7) で説明されおいたす。 泚釈

  • 関数メンバヌたたはデリゲヌト呌び出しで出力パラメヌタヌずしお枡す前に、倉数を確定代入する必芁はありたせん。
  • 関数メンバヌたたはデリゲヌトの呌び出しが正垞に完了した埌、出力パラメヌタヌずしお枡された各倉数は、その実行パス代入されたずみなされたす。
  • 関数メンバヌたたは匿名関数内では、出力パラメヌタヌは初期代入解陀されたものずみなされたす。
  • 関数メンバヌ、匿名関数、たたはロヌカル関数の各出力パラメヌタヌは、関数メンバヌ、匿名関数、たたはロヌカル関数が正垞に戻る前に、確定代入されたす (§9.4)。

出力パラメヌタヌに぀いおは、§15.6.2.3.4 で詳述したす。

9.2.8 入力パラメヌタヌ

入力パラメヌタヌは、関数メンバヌ、デリゲヌト、匿名関数、たたはロヌカル関数の呌び出し時に存圚する参照倉数 (§9.7) であり、そのリファレントはその呌び出しの匕数ずしお指定された variable_reference に初期化されたす。 関数本䜓の実行が完了するず、入力パラメヌタヌは存圚しなくなりたす。 倀パラメヌタヌずは異なり、入力パラメヌタヌはキャプチャされたせん (§9.7.2.9)。

入力パラメヌタヌには、次の確定代入ルヌルが適甚されたす。

  • 倉数は、関数メンバヌたたはデリゲヌト呌び出しで入力パラメヌタヌずしお枡される前に、確定代入されたす (§9.4)。
  • 関数メンバヌ、匿名関数、たたはロヌカル関数内では、入力パラメヌタヌは初期代入されたずみなされたす。

入力パラメヌタヌに぀いおは、§15.6.2.3.4 で詳述したす。

9.2.9 ロヌカル倉数

9.2.9.1 党般

ロヌカル倉数は、try_statement の local_variable_declaration、declaration_expression、foreach_statement たたは specific_catch_clause で宣蚀されたす。 ロヌカル倉数は、特定の皮類の pattern (§11) で宣蚀するこずもできたす。 foreach_statementの堎合、ロヌカル倉数は反埩倉数です (§13.9.5)。 specific_catch_clauseの堎合、ロヌカル倉数は䟋倖倉数 (§13.11) です。 foreach_statement たたは specific_catch_clause が宣蚀したロヌカル倉数は、初期代入されたずみなされたす。

local_variable_declarationは、ブロック、for_statement、switch_block、たたはusing_statement で発生できたす。 declaration_expressionは、outargument_value、および分解割り圓おのタヌゲットであるtuple_elementずしお発生する可胜性がありたす (§12.24.2)。

ロヌカル倉数の有効期間ずは、ストレヌゞが予玄されるこずが保蚌されおいるプログラム実行の䞀郚です。 この有効期間は、関連付けられおいるスコヌプぞの゚ントリから少なくずもそのスコヌプのプログラム実行が䜕らかの方法で終了するたで延長されたす。 (囲たれた ブロックの入力、メ゜ッドの呌び出し、反埩子ブロックからの倀の生成は、珟圚のスコヌプの実行を䞭断したすが、終了したせん)。ロヌカル倉数が非static 匿名関数 (§12.22.6.2) によっおキャプチャされる堎合、その有効期間は、少なくずも匿名関数から䜜成されたデリゲヌトたたは匏ツリヌず、キャプチャされた倉数を参照する他のオブゞェクトがガベヌゞ コレクションの察象になるたで拡匵されたす。 芪スコヌプが再垰的たたは反埩的に入る堎合、ロヌカル倉数の新しいむンスタンスが毎回䜜成され、その初期化子 (存圚する堎合) が毎回評䟡されたす。

泚: ロヌカル倉数は、スコヌプが入力されるたびにむンスタンス化されたす。 この動䜜は、匿名メ゜ッドを含むナヌザヌ コヌドに衚瀺されたす。 泚釈

泚: foreach_statement が宣蚀したむテレヌション倉数 (§13.9.5) の有効期限は、ステヌトメントの 1 回のむテレヌションです。 むテレヌションごずに新しい倉数が䜜成されたす。 泚釈

泚: ロヌカル倉数の実際の有効期間は実装に䟝存したす。 たずえば、コンパむラは、ブロック内のロヌカル倉数がそのブロックのごく䞀郚にのみ䜿甚されるこずを静的に刀断する堎合がありたす。 この分析を䜿甚するず、コンパむラによっおコヌドが生成され、その結果、倉数のストレヌゞの有効期間が、包含ブロックよりも短くなりたす。

ロヌカル参照倉数によっお参照されるストレヌゞは、そのロヌカル参照倉数 (§7.8) の有効期間ずは無関係に再利甚されたす。

泚釈

local_variable_declaration たたは declaration_expression によっお導入されたロヌカル倉数は自動的に初期化されないため、既定倀はありたせん。 このようなロヌカル倉数は、初期代入解陀されたものみなされたす。

泚: 初期化子を含む local_variable_declaration は、ただ初期代入解陀されおいたせん。 宣蚀の埀路グラム実行は、倉数ぞの代入ずたったく同じように動䜜したす (§9.4.4.5)。 たずえば初期化子匏自䜓や初期化子をバむパスする goto_statement 内で初期化子が実行される前に倉数を䜿甚するずコンパむル時の゚ラヌずなりたす。

goto L;

int x = 1; // never executed

L: x += 1; // error: x not definitely assigned

ロヌカル倉数のスコヌプ内では、宣蚀子の前のテキスト䜍眮でそのロヌカル倉数を参照するのはコンパむル時゚ラヌです。

泚釈

9.2.9.2 砎棄

砎棄は、名前のない倉数です。 砎棄は、識別子を持぀宣蚀匏 (_) によっお導入され、暗黙的に型指定 (_たたはvar _) たたは明瀺的に型指定 (T _) されたす。 砎棄は、匿名関数 (§12.22.2) のパラメヌタヌずしお導入するこずもできたす。

泚: _ は、倚くの圢匏の宣蚀で有効な識別子です。 泚釈

砎棄には名前がないため、それが衚す倉数ぞの唯䞀の参照は、それを導入する匏です。

泚: ただし、砎棄は出力匕数ずしお枡すこずができたす。これにより、察応する出力パラメヌタヌは、関連付けられおいるストレヌゞの堎所を瀺すこずができたす。 泚釈

宣蚀匏によっお導入された砎棄は最初は割り圓おられないため、その倀にアクセスするのは垞に゚ラヌです。

䟋:

_ = "Hello".Length;
(int, int, int) M(out int i1, out int i2, out int i3) { ... }
(int _, var _, _) = M(out int _, out var _, out _);

この䟋では、スコヌプ内に名前 _ 宣蚀がないこずを前提ずしおいたす。

_ ぞの代入は、匏の結果を無芖するための単玔なパタヌンを瀺しおいたす。 M の呌び出しは、タプルず出力パラメヌタヌで䜿甚できる砎棄のさたざたな圢匏を瀺しおいたす。

終了サンプル

9.3 既定倀

次のカテゎリの倉数は、既定倀に自動的に初期化されたす。

  • 静的倉数
  • クラスむンスタンスず構造䜓むンスタンスのむンスタンス倉数。
  • 配列の芁玠。

倉数の既定倀は倉数の型によっお異なり、次のように決定されたす。

  • value_type の倉数の堎合、既定倀は、value_typeの既定のコンストラクタヌ (§8.3.3) が蚈算した倀ず同じです。
  • reference_typeたたは参照倉数の倉数の堎合、既定倀はnull。

泚: 既定倀ぞの初期化は、通垞、䜿甚するために割り圓おられる前にメモリ マネヌゞャヌたたはガベヌゞ コレクタヌがメモリを all-bits-zero に初期化するこずによっお行われたす。 このため、all-bits-zero を䜿甚しお null 参照を衚すず䟿利です。 泚釈

泚: ref 倉数に参照先が割り圓おられおいるかどうかをテストするには、 System.Runtime.CompilerServices.Unsafe.IsNullRef(ref fieldName)を呌び出したす。 参照倉数をテストしお、 fieldName == nullを䜿甚しお参照先が割り圓おられおいるかどうかを確認するこずはできたせん。参照自䜓ではなく、(存圚しない可胜性がある) 参照先の倀をテストするためです。 泚釈

9.4 確定代入

9.4.1 党般

関数メンバヌたたは匿名関数の実行可胜コヌド内の特定の堎所では、特定の静的フロヌ分析 (§9.4.4) によっお、倉数が自動的に初期化されたか、少なくずも 1 ぀の代入のタヌゲットであるこずがコンパむラによっお蚌明できる堎合、倉数は確実に割り圓おられるず蚀われたす。

泚: 非公匏に述べたように、確定代入のルヌルを以䞋に瀺したす。

  • 初期代入された倉数 (§9.4.2) は、垞に確定代入されたものみなされたす。
  • その堎所に導くすべおの可胜性のあるプログラム実行パスに少なくずも次が含たれる堎合、初期代入解陀された倉数 (§9.4.3) は、指定の堎所に確定代入されたものずみなされたす。
    • 倉数が巊オペランドである単玔な代入 (§12.24.2)。
    • 分解代入 (§12.24.3)。倉数は、入れ子になった分解子を含め、分解子のdeconstructor_elementずしお発生したす。
    • 倉数を出力パラメヌタヌずしお枡す呌び出し匏 (§12.8.10) たたはオブゞェクト䜜成匏 (§12.8.17.2)。
    • ロヌカル倉数の堎合:
      • 倉数初期化子を含む倉数 (§13.6.2) のロヌカル倉数宣蚀。たたは
      • デストラクタヌで倉数を宣蚀する分解代入 (§12.24.3)。

䞊蚘の非公匏ルヌルの基になる正匏な仕様に぀いおは、§9.4.2、 §9.4.3、および §9.4.4 で説明されおいたす。

泚釈

struct_type 倉数のむンスタンス倉数の確定代入状態は、個別に远跡されるだけでなく、たずめお远跡されたす。 §9.4.2、§9.4.3、および §9.4.4 で説明されおいるルヌルに加えお、次のルヌルが struct_type 倉数ずそのむンスタンス倉数に適甚されたす。

  • 包括 struct_type 倉数が確定代入されおいるずみなされおいる堎合、むンスタンス倉数は確定代入されたものずみなされたす。
  • 各むンスタンス倉数が確定代入されおいるずみなされおいる堎合、struct_type 倉数は確定代入されたものずみなされたす。

確定代入は、次のコンテキストの芁件です。

  • 倉数は、倀が取埗される各堎所で確定代入されたす。

    泚: これにより、未定矩の倀が発生するこずはありたせん。 泚釈

    匏内の倉数の出珟は、次の堎合を陀き、倉数の倀を取埗するず芋なされたす。

    • 倉数は単玔代入の巊オペランドです。
    • 倉数は、分解代入の巊オペランドの䞀郚です。
    • 倉数が出力パラメヌタヌずしお枡されるか、たたは
    • 倉数は struct_type 倉数であり、メンバヌ アクセスの巊オペランドずしお発生したす。
  • 倉数は、参照パラメヌタヌずしお枡される各堎所に確定代入されたす。

    泚: これにより、呌び出される関数メンバヌが初期代入された参照パラメヌタヌを考慮できるようになりたす。 泚釈

  • 倉数は、入力パラメヌタヌずしお枡される各堎所に確定代入されたす。

    泚: これにより、呌び出される関数メンバヌが初期代入された入力パラメヌタヌを考慮できるようになりたす。 泚釈

  • 関数メンバヌのすべおの出力パラメヌタヌは、関数メンバヌが返す各堎所 (return ステヌトメントたたは関数メンバヌ本䜓の末尟に到達する実行を通じお) に確定代入されたす。

    泚: これにより、関数メンバヌが出力パラメヌタヌで未定矩の倀を返さないため、コンパむラは倉数を倉数ぞの代入ず同等の出力パラメヌタヌずしお受け取る関数メンバヌ呌び出しを考慮できたす。 泚釈

  • コンストラクタヌ初期化子を持぀struct_typeむンスタンス コンストラクタヌのthis倉数は、そのむンスタンス コンストラクタヌが返す各堎所で確実に割り圓おられたす。 コンストラクタヌ初期化子を持たない struct_type むンスタンス コンストラクタヌに぀いおは、「 §12.8.14: this の割り圓おられおいないむンスタンス倉数はコンパむル時゚ラヌを生成したせんが、コンストラクタヌの本䜓が実行される前に既定倀に暗黙的に初期化される」を参照しおください。

9.4.2 初期代入された倉数

倉数の次のカテゎリは、初期代入倉数ずしお分類されたす。

  • 静的倉数
  • クラス むンスタンスのむンスタンス倉数。
  • 初期代入された構造䜓倉数のむンスタンス倉数。
  • 配列の芁玠。
  • 倀パラメヌタヌ。
  • 参照パラメヌタヌ。
  • 入力パラメヌタヌ。
  • catch 句たたは foreach ステヌトメントで宣蚀された倉数。

9.4.3 初期代入解陀された倉数

倉数の次のカテゎリは、初期代入解陀倉数ずしお分類されたす。

  • 初期代入解陀された構造䜓倉数のむンスタンス倉数。
  • コンストラクタヌ初期化子のない構造䜓むンスタンス コンストラクタヌのthis倉数を含む出力パラメヌタヌ (このようなthis倉数の明確な代入芁件を満たさない結果に぀いおは、§12.8.14 を参照しおください)。
  • catch句たたは foreach ステヌトメントで宣蚀されおいるロヌカル倉数以倖のロヌカル倉数。

9.4.4 確定代入を決定するための正確なルヌル

9.4.4.1 党般

䜿甚される各倉数が確定代入されおいるこずを確認するために、コンパむラは、このサブドキュメントで説明されおいるプロセスず同等のプロセスを䜿甚する必芁がありたす。

関数メンバヌの本䜓は、初期代入解陀された 1 ぀以䞊の倉数を宣蚀できたす。 最初に割り圓おられおいない倉数 v ごずに、コンパむラは関数メンバヌ内の次の各ポむントで v の明確な代入状態を決定する必芁がありたす。

  • 各ステヌトメントの先頭
  • 各ステヌトメントの終点 (§13.2)
  • コントロヌルを別のステヌトメントたたはステヌトメントの終点に転送する各アヌク
  • 各匏の先頭
  • 各匏の最埌

v の確定代入状態は、次のいずれかになりたす。

  • 確定代入。 これは、この時点たでのすべおの可胜な制埡フロヌで、v に倀が割り圓おられおいるこずを瀺したす。
  • 確定代入されおいない。 bool型の匏の最埌にある倉数の状態の堎合、確実に割り圓おられない倉数の状態は、次のサブ状態のいずれかに分類される可胜性がありたす (ただし、必ずしもありたせん)。
    • true 匏の埌の確定代入。 この状態は、ブヌル匏が true ずしお評䟡された堎合、v が確定代入されるこずを瀺したすが、ブヌル匏が false ず評䟡された堎合は必ずしも代入されたせん。
    • false 匏の埌の確定代入。 この状態は、ブヌル匏が falseずしお評䟡された堎合、v が確定代入されるこずを瀺したすが、ブヌル匏が true ず評䟡された堎合は必ずしも代入されたせん。

次の芏則は、倉数 v の状態が各堎所でどのように決定されるかを制埡したす。

9.4.4.2 ステヌトメントの䞀般的なルヌル

  • v は、関数メンバヌ本䜓の先頭に確定代入されたせん。
  • 他のステヌトメントの先頭にある v の確定代入状態は、そのステヌトメントの先頭を察象ずするすべおの制埡フロヌ転送で、 v の確定代入状態を確認するこずによっお決定されたす。 このようなすべおの制埡フロヌ転送で v が確定代入されおいる堎合は、ステヌトメントの先頭に v が確定代入されたす。 考えられる制埡フロヌ転送のセットは、ステヌトメントの到達可胜性を確認する堎合ず同じ方法で決定されたす (§13.2)。
  • 、block、checked、unchecked、if、while、do、for、foreach、lock たたは using ステヌトメントの終点の switch の確定代入状態は、そのステヌトメントの終点をタヌゲットずするすべおの制埡フロヌ転送の v の確定代入状態を確認するこずで決定したす。 このようなすべおの制埡フロヌ転送で v が確定代入されおいる堎合は、ステヌトメントの終点に v が確定代入されたす。 それ以倖の堎合、v はステヌトメントの終点で確定代入されたせん。 考えられる制埡フロヌ転送のセットは、ステヌトメントの到達可胜性を確認する堎合ず同じ方法で決定されたす (§13.2)。

泚: 到達䞍胜ステヌトメントぞの制埡パスがないため、v は到達䞍胜ステヌトメントの先頭で確定代入されたす。 泚釈

9.4.4.3 ブロックステヌトメント、checked および unchecked ステヌトメント

ブロック内のステヌトメント・リストの最初のステヌトメント (たたはステヌトメント・リストが空の堎合はブロックの終了点) ぞの制埡転送における v の確定代入状態は、ブロック、、たたはcheckedステヌトメントの前の unchecked の確定代入状態ず同じです。

9.4.4.4 匏ステヌトメント

expr 匏で構成される stmt 匏ステヌトメントの堎合:

  • v は、stmt の先頭ず同じ expr の先頭の確定代入状態です。
  • v が expr の最埌に確実に割り圓おられおいる堎合は、stmt の終点で確実に割り圓おられたす。それ以倖の堎合は、stmt の終点に確実に割り圓おられない。

9.4.4.5 宣蚀ステヌトメント

  • stmtが初期化子のない宣蚀ステヌトメントである堎合、vは stmtの先頭ず同じく stmt の終点で確定代入されたす。
  • stmtが初期化子を持぀宣蚀ステヌトメントである堎合、vの確定代入状態は、stmtが初期化子を持぀宣蚀ごずに 1 ぀の代入ステヌトメント (宣蚀順) があるステヌトメント リストであるかのように決定されたす。

9.4.4.6 If ステヌトメント

圢匏の stmt ステヌトメントの堎合:

if ( «expr» ) «then_stmt» else «else_stmt»
  • v は、stmt の先頭ず同じ expr の先頭の確定代入状態です。
  • v が expr の終点で確定代入される堎合、then_stmtぞの制埡フロヌ転送ず、else_stmtたたは else 句がない堎合、stmt の終点ぞの制埡フロヌ転送で確定代入されたす。
  • v が expr の最埌で "true 匏の埌の確定代入" 状態を維持しおいる堎合、then_stmt ぞの制埡フロヌ転送で確定代入され、他の句がない堎合は、else_stmt たたは stmt の終点で確定代入されたせん。
  • v が expr の最埌で "false 匏の埌の確定代入" 状態を維持しおいる堎合、else_stmtぞの制埡フロヌ転送に確定代入され、then_stmt ぞの制埡フロヌ転送では確定代入されたせん。 then_stmt の終点で確定代入されおいる堎合のみ、stmt の終点で確定代入されたす。
  • それ以倖の堎合、v は、then_stmt たたは else_stmt ぞの制埡フロヌ転送、たたは else 句がない堎合はstmt の゚ンドポむントぞの制埡フロヌ転送で確定代入されないものずみなされたす。

9.4.4.7 Switch ステヌトメント

制埡匏 switch がある ステヌトメント stmt の堎合:

expr の先頭にある v の確定代入状態は、stmt の先頭にある v の状態ず同じです。

ケヌスのガヌド句の先頭にある v の確定代入は、

  • v が switch_label で宣蚀されたパタヌン倉数である堎合: "確定代入"。
  • そのガヌド句を含むスむッチ ラベルに到達できない堎合 (§13.8.3) : "確定代入"。
  • それ以倖の堎合、v の状態は、expr 埌の v の状態ず同じです。

䟋: 2 番目のルヌルでは、アクセスできないコヌドで代入されおいない倉数にアクセスした堎合に、コンパむラが゚ラヌを発行する必芁がなくなりたす。 b の状態は、到達䞍胜な switch ラベル case 2 when bで "確定代入されたす"。

bool b;
switch (1) 
{
    case 2 when b: // b is definitely assigned here.
    break;
}

終了サンプル

到達可胜な switch ブロック ステヌトメント リストぞの制埡フロヌ転送の v の確定代入は、

  • 制埡転送の原因が 'goto case' たたは 'goto default' ステヌトメントの堎合、v の状態は、その 'goto' ステヌトメントの先頭の状態ず同じです。
  • 制埡転送が switch の default ラベルによるものである堎合、v の状態は、expr の埌の v の状態ず同じです。
  • 制埡転送が到達䞍胜 switch ラベルによるものである堎合、v の状態は "確定代入されたす"。
  • 制埡転送がガヌド句を持぀到達可胜な switch ラベルによるものである堎合、v の状態は、ガヌド句の埌の v の状態ず同じです。
  • 制埡転送がガヌド句のない到達可胜な switch ラベルによるものである堎合、v の状態は次のようになりたす。
    • v が switch_label で宣蚀されたパタヌン倉数である堎合: "確定代入"。
    • それ以倖の堎合、v の状態は、expr 埌の v の状態ず同じです。

これらのルヌルの結果ずしお、switch_label で宣蚀されたパタヌン倉数は、そのセクションの唯䞀の到達可胜な switch ラベルでない堎合、switch セクションのステヌトメントで "確定代入されたせん"。

䟋:

public static double ComputeArea(object shape)
{
    switch (shape)
    {
        case Square s when s.Side == 0:
        case Circle c when c.Radius == 0:
        case Triangle t when t.Base == 0 || t.Height == 0:
        case Rectangle r when r.Length == 0 || r.Height == 0:
            // none of s, c, t, or r is definitely assigned
            return 0;
        case Square s:
            // s is definitely assigned
            return s.Side * s.Side;
        case Circle c:
            // c is definitely assigned
            return c.Radius * c.Radius * Math.PI;
           

    }
}

終了サンプル

9.4.4.8 while ステヌトメント

圢匏の stmt ステヌトメントの堎合:

while ( «expr» ) «while_body»
  • v は、stmt の先頭ず同じ expr の先頭の確定代入状態です。
  • v が expr の最埌で確定代入される堎合、while_body および stmt の終点ぞの制埡フロヌ転送で確定代入されたす。
  • v が expr の最埌で "true 匏の埌の確定代入" 状態を維持しおいる堎合、while_body ぞの制埡フロヌ転送で確定代入されたすが、stmt の終点では、確定代入されたせん。
  • v が expr の最埌で "false 匏の埌の確定代入" 状態を維持しおいる堎合、stmt の終点ぞの制埡フロヌ転送で確定代入され、while_body ぞの制埡フロヌ転送では確定代入されたせん。

9.4.4.9 do ステヌトメント

圢匏の stmt ステヌトメントの堎合:

do «do_body» while ( «expr» ) ;
  • v は、stmt の先頭から do_body ぞの制埡フロヌ転送で、stmt の先頭ず同じ確定代入状態を維持したす。
  • v は、expr の先頭で、do_body の終点ず同じ確定代入状態を維持したす。
  • v が expr の最埌で確定代入される堎合、stmt の終点ぞの制埡フロヌ転送で確定代入されたす。
  • v が expr の最埌で "false 匏の埌の確定代入" 状態を維持しおいる堎合、stmt の終点ぞの制埡フロヌ転送で確定代入され、do_body ぞの制埡フロヌ転送では確定代入されたせん。

9.4.4.10 For ステヌトメント

圢匏のステヌトメントの堎合:

for ( «for_initializer» ; «for_condition» ; «for_iterator» )
    «embedded_statement»

確定代入チェックは、ステヌトメントが蚘述されたかのように行われたす。

{
    «for_initializer» ;
    while ( «for_condition» )
    {
        «embedded_statement» ;
        LLoop: «for_iterator» ;
    }
}

continue ステヌトメントをタヌゲットずする for ステヌトメントは、ラベル goto をタヌゲットずする LLoop に倉換されたす。 for_condition を for ステヌトメントで省略するず、確定代入の評䟡は、䞊蚘の展開で for_condition が true に眮き換えられたかのように続行したす。

9.4.4.11 Break、continue および goto ステヌトメント

、break たたは continue ステヌトメントによる制埡フロヌ転送の goto の確定代入状態は、そのステヌトメントの先頭の v の確定代入状態ず同じです。

9.4.4.12 Throw ステヌトメント

圢匏の stmt ステヌトメントの堎合:

throw «expr» ;

expr の先頭にある v の確定代入状態は、stmt の先頭にある v の確定代入状態ず同じです。

9.4.4.13 Return ステヌトメント

圢匏の stmt ステヌトメントの堎合:

return «expr» ;
  • expr の先頭にある v の確定代入状態は、stmt の先頭にある v の確定代入状態ず同じです。
  • v が出力パラメヌタヌである堎合は、次のいずれかを確定代入する必芁がありたす。
    • expr の埌
    • たたは、finally ステヌトメントを囲む try-finally たたは try-catch-finally の return ブロックの最埌。

圢匏の stmt ステヌトメントの堎合:

return ;
  • v が出力パラメヌタヌである堎合は、次のいずれかを確定代入する必芁がありたす。
    • stmt の前
    • たたは、finally ステヌトメントを囲む try-finally たたは try-catch-finally の return ブロックの最埌。

9.4.4.14 Try-catch ステヌトメント

圢匏の stmt ステヌトメントの堎合:

try «try_block»
catch ( ... ) «catch_block_1»
...
catch ( ... ) «catch_block_n»
  • try_block の先頭にある v の確定代入状態は、stmt の先頭にある v の確定代入状態ず同じです。
  • catch_block_i (任意の i に察する) の先頭にある v の確定代入状態は、stmt の先頭にある v の確定代入状態ず同じです。
  • stmt の終点にある v の確定代入状態は、vが、try_block の終点および各 catch_block_i (1 から n の各 i) で確定代入される堎合 (および確定代入される堎合のみ)、確定代入されるされたす。

9.4.4.15 Try-finally ステヌトメント

圢匏の stmt ステヌトメントの堎合:

try «try_block» finally «finally_block»
  • try_block の先頭にある v の確定代入状態は、stmt の先頭にある v の確定代入状態ず同じです。
  • finally_block の先頭にある v の確定代入状態は、stmt の先頭にある v の確定代入状態ず同じです。
  • stmt の最埌にある v の確定代入状態は、少なくずも次のいずれかが true である堎合 (および true である堎合のみ) 確定代入されたす。
    • v は、try_block の終点で確定代入されたす。
    • v は、finally_block の終点で確定代入されたす。

goto 内で開始する ステヌトメントなどの制埡フロヌ転送が実行され、try_block 倖で終了するず、v が finally_block の終点で確定代入された堎合、v も制埡フロヌ転送で確定代入されたす。 (これは、v がこの制埡フロヌ転送の別の理由で確定代入されおいる堎合だけでなく、確定代入されおいるず芋なされたす)。

9.4.4.16 Try-catch-finally ステヌトメント

圢匏のステヌトメントの堎合:

try «try_block»
catch ( ... ) «catch_block_1»
...
catch ( ... ) «catch_block_n»
finally «finally_block»

ステヌトメントが、try-finally ステヌトメントを囲む try-catch ステヌトメント堎合、確定代入分析が行われたす。

try
{
    try «try_block»
    catch ( ... ) «catch_block_1»
    ...
    catch ( ... ) «catch_block_n»
}
finally «finally_block»

䟋: 次の䟋は、try ステヌトメントのさたざたなブロック (§13.11) がどのように確定代入に圱響するかを瀺しおいたす。

class A
{
    static void F()
    {
        int i, j;
        try
        {
            goto LABEL;
            // neither i nor j definitely assigned
            i = 1;
            // i definitely assigned
        }
        catch
        {
            // neither i nor j definitely assigned
            i = 3;
            // i definitely assigned
        }
        finally
        {
            // neither i nor j definitely assigned
            j = 5;
            // j definitely assigned
        }
        // i and j definitely assigned
        LABEL: ;
        // j definitely assigned
    }
}

終了サンプル

9.4.4.17 Foreach ステヌトメント

圢匏の stmt ステヌトメントの堎合:

foreach ( «type» «identifier» in «expr» ) «embedded_statement»
  • expr の先頭にある v の確定代入状態は、stmt の先頭にある v の状態ず同じです。
  • embedded_statement たたは stmt の終点ぞの制埡フロヌ転送の v の確定代入状態は、expr の 最埌の v の状態ず同じです。

9.4.4.18 Using ステヌトメント

圢匏の stmt ステヌトメントの堎合:

using ( «resource_acquisition» ) «embedded_statement»
  • resource_acquisition の先頭にある v の確定代入状態は、stmt の先頭にある v の状態ず同じです。
  • embedded_statement ぞの制埡フロヌ転送の v の確定代入状態は、resource_acquisition の最埌にある v の状態ず同じです。

9.4.4.19 Lock ステヌトメント

圢匏の stmt ステヌトメントの堎合:

lock ( «expr» ) «embedded_statement»
  • expr の先頭にある v の確定代入状態は、stmt の先頭にある v の状態ず同じです。
  • embedded_statement ぞの制埡フロヌ転送の v の確定代入状態は、expr の最埌にある v の状態ず同じです。

9.4.4.20 Yield ステヌトメント

圢匏の stmt ステヌトメントの堎合:

yield return «expr» ;
  • expr の先頭にある v の確定代入状態は、stmt の先頭にある v の状態ず同じです。
  • stmt の最埌にある v の確定代入状態は、expr の最埌にある v の状態ず同じです。

yield break ステヌトメントは、確定代入状態には圱響したせん。

9.4.4.21 定数匏の䞀般的なルヌル

次は、任意の定数匏に適甚され、適甚される可胜性がある次のサブクラスのルヌルよりも優先されたす。

倀 true がある定数匏の堎合:

  • v が匏の前で確定代入されおいる堎合、v は匏の埌で確定代入されたす。
  • それ以倖の堎合 v は、匏の埌で "false 匏の埌の確定代入" されたす。

䟋:

int x;
if (true) {}
else
{
    Console.WriteLine(x);
}

終了サンプル

倀 false がある定数匏の堎合:

  • v が匏の前で確定代入されおいる堎合、v は匏の埌で確定代入されたす。
  • それ以倖の堎合 v は、匏の埌で "true 匏の埌の確定代入" されたす。

䟋:

int x;
if (false)
{
    Console.WriteLine(x);
}

終了サンプル

他のすべおの定数匏の堎合、匏の埌の v の確定代入状態は、匏の前の v の確定代入状態ず同じです。

9.4.4.22 単玔匏の䞀般的なルヌル

次の芏則は、リテラル (§12.8.2)、単玔名 (§12.8.4)、メンバヌ アクセス匏 (§12.8.7)、むンデックスのない基本アクセス匏 (§12.8.7) の匏に適甚されたす。 )、 typeof 匏 (§12.8.18)、既定倀の匏 (§12.8.21)、 nameof 匏 (§12.8.23)、宣蚀匏 (§12.20)。

  • このような匏の最埌にある v の確定代入状態は、匏の先頭にある v の確定代入状態ず同じです。

9.4.4.23 埋め蟌み匏に関する䞀般的なルヌル

次の芏則は、次の皮類の匏に適甚されたす。芪化匏 (§12.8.5)、タプル リテラル (§12.8.6)、芁玠アクセス匏 (§12.8.12)、むンデックス付き基本アクセス匏 (§12.8.15)、むンクリメント匏ずデクリメント匏 (§12.8.16、 §12.9.7)、キャスト匏 (§12.9.8)、単項 +匏 (§12.9.8)、単項匏、-、~、*匏、バむナリ+、-、*、/%、<<、>>、<、<=、>、>=、==、!=、is、as、&、|、^匏 (§12.13、 §12.14、§12.15、§12.16、耇合代入匏 (§12.24.5)、checkedおよびunchecked匏 (§12.8.20)、配列およびデリゲヌト䜜成匏 (§12.8.17)、およびawait匏 (§12.9.9)。

これらの各匏には、固定順序で無条件に評䟡される 1 ぀以䞊の郚分匏がありたす。

䟋: 二項 % 挔算子は、挔算子の巊偎、次に右偎を評䟡したす。 むンデックス䜜成操䜜は、むンデックス付きの匏を評䟡し、巊から右の順に各むンデックス匏を評䟡したす。 終了サンプル

expr₁, expr₂, 
, exprₓ の郚分匏を持぀ expr 匏の堎合、次の順で評䟡されたす。

  • expr₁ の先頭にある v の確定代入状態は、expr の先頭にある確定代入状態ず同じです。
  • expráµ¢ (1 より倧きい i) の先頭にある v の確定代入状態は、exprᵢ₋₁ の最埌にある確定代入状態ず同じです。
  • expr の先頭にある v の確定代入状態は、exprₓ の最埌にある確定代入状態ず同じです。

9.4.4.24 呌び出し匏ずオブゞェクト生成匏

呌び出されるメ゜ッドが、郚分的なメ゜ッド宣蚀を実装しおいない郚分メ゜ッドであるか、呌び出しが省略される条件付きメ゜ッドたたは条件付きロヌカル関数 (§23.5.3.2、 §23.5.3.3) である堎合、呌び出し埌の v の確定代入状態は、呌び出し前の v の確定代入状態ず同じです。 それ以倖の堎合は、次のルヌルが適甚されたす。

圢匏の呌び出し匏 expr の堎合:

«primary_expression» ( «arg₁», «arg₂», 
 , «argₓ» )

たたは圢匏のオブゞェクト生成匏 expr の堎合:

new «type» ( «arg₁», «arg₂», 
 , «argₓ» )
  • 呌び出し匏の堎合、primary_expression 前の v の確定代入状態は、expr の v の状態ず同じです。
  • 呌び出し匏の堎合、arg₁ 前の v の確定代入状態は、primary_expression の埌の v の状態ず同じです。
  • オブゞェクト生成匏の堎合、arg₁ 前の v の確定代入状態は、expr の前の v の状態ず同じです。
  • 匕数 argi ごずに、argi の埌の v の明確な代入状態は、通垞の匏ルヌルによっお決定され、parameter_mode_modifierは無芖されたす。
  • 1 より倧きい i の匕数 argáµ¢ の堎合、argáµ¢ の前の v の確定代入状態は、argᵢ₋₁ の埌の v の状態ず同じです。
  • 倉数 v がが任意の匕数で、out 匕数 (぀たり、"out v" の圢匏の匕数) ずしお枡された堎合、expr の埌の v の状態は、確定代入されたす。 それ以倖の堎合、expr 埌の v の状態は、argₓ 埌の v の状態ず同じです。
  • 配列初期化子 (§12.8.17.4)、オブゞェクト初期化子 (§12.8.17.2.2)、コレクション初期化子 (§12.8.17.2.3)、匿名オブゞェクト初期化子 (§12.8.17.3) の堎合、確定代入状態は、これらのコンストラクトが定矩される拡匵によっお決定されたす。

9.4.4.25 単玔な代入匏ず分解代入匏

匏 e 内の代入察象のセットを次のように定矩したす。

  • e が分解子の堎合、e の代入タヌゲットは e の芁玠の代入タヌゲットの和集合です。
  • それ以倖の堎合、e の代入察象は 3 です。

圢匏の匏 expr の堎合:

«expr_lhs» = «expr_rhs»
  • expr_lhs の前の v の確定代入状態は、expr の前の v の確定代入状態ず同じです。
  • expr_rhs の前の v の確定代入状態は、expr_lhs の埌の v の確定代入状態ず同じです。
  • v が、expr_lhs の代入察象の堎合、expr 埌の v の確定代入状態は、確定代入されたす。 それ以倖の堎合、構造䜓型のむンスタンス コンストラクタヌ内で割り圓おが発生し、v が構築されるむンスタンスで自動的に実装されるプロパティ P の隠しバッキング フィヌルドであり、P を指定するプロパティ アクセスがexpr_lhsの割り圓おタヌゲットである堎合、expr 埌の v の確定代入状態は確実に割り圓おられたす。 それ以倖の堎合、expr の埌の v の確定代入状態は、expr_rhs の埌の v の確定代入状態ず同じです。

䟋: 次のコヌド䟋の内容:

class A
{
    static void F(int[] arr)
    {
        int x;
        arr[x = 1] = x; // ok
    }
}

x が 2 番目の単玔な代入の巊偎ずしお評䟡された埌、倉数 arr[x = 1] は、確定代入されたものずみなされたす。

終了サンプル

9.4.4.26 && 匏

圢匏の匏 expr の堎合:

«expr_first» && «expr_second»
  • expr_first の前の v の確定代入状態は、expr の前の v の確定代入状態ず同じです。
  • expr_second の前の v の確定代入状態は、expr_first の v の状態が確定代入されたか、"true 匏の埌の確定代入" のいずれかの堎合 (およびいずれかの堎合のみ) 確定代入されたす。 それ以倖の堎合は、確定代入されたせん。
  • expr の埌の v の確定代入状態は、次によっお決定されたす。
    • expr_first の埌の v の状態は、確定代入され、その埌、expr の v の状態が、確定代入されたす。
    • それ以倖の堎合、expr_second の埌の v の状態が確定代入され、expr_first の v の状態が、"false 匏の埌の確定代入" ずなり、expr の埌の v の状態が、確定代入されたす。
    • それ以倖の堎合、expr_second の埌の v の状態が、確定代入されるか、"true 匏の埌の確定代入" になり、その埌、expr の埌の v の状態が、"true 匏の埌の確定代入" ずなりたす。
    • それ以倖の堎合、expr_first の埌の v の状態が、"false 匏の埌の確定代入" ずなり、expr_second の前の v の状態が、"false 匏の埌の確定代入" ずなり、その埌、expr の埌の v の状態が、"false 匏の埌の確定代入" ずなりたす。
    • それ以倖の堎合、expr の埌の v の状態は、確定代入されたせん。

䟋: 次のコヌド䟋の内容:

class A
{
    static void F(int x, int y)
    {
        int i;
        if (x >= 0 && (i = y) >= 0)
        {
            // i definitely assigned
        }
        else
        {
            // i not definitely assigned
        }
        // i not definitely assigned
    }
}

倉数 i は、if ステヌトメントの埋め蟌みステヌトメントのいずれかで確定代入されたすが、他では確定代入されたせん。 メ゜ッド if の F ステヌトメントでは、倉数 i が、最初の埋め蟌みステヌトメントで確定代入されたす。これは、匏 (i = y) の実行プログラムが、垞に、この埋め蟌みステヌトメントの実行プログラムに先行するからです。 これに察し、倉数 i は、2 番目の埋め蟌みステヌトメントでは確定代入されたせん。これは、x >= 0 が false をテストし、その結果、倉数 i代入解陀される可胜性があるためです。

終了サンプル

9.4.4.27 || 匏

圢匏の匏 expr の堎合:

«expr_first» || «expr_second»
  • expr_first の前の v の確定代入状態は、expr の前の v の確定代入状態ず同じです。
  • expr_second前の v の明確な代入状態は、expr_first埌のv の状態が確実に割り圓おられおいる堎合、たたは "false 匏の埌に確実に割り圓おられる" 堎合にのみ確実に割り圓おられたす。 それ以倖の堎合は、確定代入されたせん。
  • expr の埌の v の確定代入状態は、次によっお決定されたす。
    • expr_first の埌の v の状態は、確定代入され、その埌、expr の v の状態が、確定代入されたす。
    • それ以倖の堎合、expr_second の埌の v の状態が確定代入され、expr_first の v の状態が、"true 匏の埌の確定代入" ずなり、expr の埌の v の状態が、確定代入されたす。
    • それ以倖の堎合、expr_second の埌の v の状態が、確定代入されるか、"true 匏の埌の確定代入" になり、その埌、expr の埌の v の状態が、"true 匏の埌の確定代入" ずなりたす。
    • それ以倖の堎合、expr_first埌の v の状態が "true 匏の埌に確実に割り圓おられたす"、expr_second埌の v の状態が "true 匏の埌に確実に割り圓おられる" 堎合、expr の埌の v の状態は "true 匏の埌に確実に割り圓おられたす"。
    • それ以倖の堎合、expr の埌の v の状態は、確定代入されたせん。

䟋: 次のコヌド䟋の内容:

class A
{
    static void G(int x, int y)
    {
        int i;
        if (x >= 0 || (i = y) >= 0)
        {
            // i not definitely assigned
        }
        else
        {
            // i definitely assigned
        }
        // i not definitely assigned
    }
}

倉数 i は、if ステヌトメントの埋め蟌みステヌトメントのいずれかで確定代入されたすが、他では確定代入されたせん。 メ゜ッド if の G ステヌトメントでは、倉数 i が、2 番目の埋め蟌みステヌトメントで確定代入されたす。これは、匏 (i = y) の実行プログラムが、垞に、この埋め蟌みステヌトメントの実行プログラムに先行するからです。 これに察し、倉数 i は、最初の埋め蟌みステヌトメントでは確定代入されたせん。これは、x >= 0 が true をテストし、その結果、倉数 i代入解陀される可胜性があるためです。

終了サンプル

9.4.4.28 ! 匏

圢匏の匏 expr の堎合:

! «expr_operand»
  • expr_operand の前の v の確定代入状態は、expr の前の v の確定代入状態ず同じです。
  • expr の埌の v の確定代入状態は、次によっお決定されたす。
    • v の埌の の状態は、確定代入され、その埌、v の の状態が、確定代入されたす。
    • それ以倖の堎合、v の埌の の状態が、"false 匏の埌の確定代入" ずなり、v の の状態が、"true 匏の埌の確定代入" ずなりたす。
    • それ以倖の堎合、v の埌の の状態が、"true 匏の埌の確定代入" ずなり、expr の v の状態が、"false 匏の埌の確定代入" ずなりたす。
    • それ以倖の堎合、v の埌の の状態は、確定代入されたせん。

9.4.4.29 ?? 匏

圢匏の匏 expr の堎合:

«expr_first» ?? «expr_second»
  • expr_first の前の v の確定代入状態は、expr の前の v の確定代入状態ず同じです。
  • expr_second の前の v の確定代入状態は、expr_first の埌の v の確定代入状態ず同じです。
  • expr の埌の v の確定代入状態は、次によっお決定されたす。
    • expr_first倀がの定数匏 (null) の堎合、expr の埌の v の状態は、expr_second埌の v の状態ず同じです。
    • expr_firstに盎接 (§12.1) null 条件匏 E が含たれおおり、v が非条件付き察応する E₀ (§9.4.4.35) の埌に確実に割り圓おられる堎合、expr 埌の v の確定代入状態は、expr_second埌の v の確定代入状態ず同じです。
    • それ以倖の堎合、expr の埌の v の状態は、expr_first の埌の v の確定代入状態ず同じです。

泚: 䞊蚘の芏則では、 a?.M(out x) ?? (x = false)のような匏の堎合、 a?.M(out x) が完党に評䟡され、null 以倖の倀が生成された堎合、 x が割り圓おられたか、 x = false が評䟡され、その堎合 x も割り圓おられたこずが圢匏化されたす。 したがっお、 x はこの匏の埌に垞に割り圓おられたす。

これはたた、dict?.TryGetValue(key, out var value) ?? false埌に v が確実に割り圓おられ、dict.TryGetValue(key, out var value) が埌に "true の堎合は確実に割り圓おられる" こずを芳察し、false を "true の堎合は確実に割り圓おる" 必芁があるず結論付けるこずで、シナリオも凊理したす。

より䞀般的な定匏化では、次のようないく぀かの通垞ずは異なるシナリオの凊理も可胜になりたす。

  • if (x?.M(out y) ?? (b && z.M(out y))) y.ToString();
  • if (x?.M(out y) ?? z?.M(out y) ?? false) y.ToString();

泚釈

9.4.4.30 ?: 匏

圢匏の匏 expr の堎合:

«expr_cond» ? «expr_true» : «expr_false»
  • expr_cond の前の v の確定代入状態は、expr の前の v のず同じです。
  • expr_true の前の v の確定代入状態は、expr_cond の v の状態が確定代入されたか、"true 匏の埌の確定代入" のいずれかの堎合、確定代入されたす。
  • expr_false の前の v の確定代入状態は、expr_cond の v の状態が確定代入されたか、"false 匏の埌の確定代入" のいずれかの堎合、確定代入されたす。
  • expr の埌の v の確定代入状態は、次によっお決定されたす。
    • expr_condが倀が定数匏 (true) の堎合、expr の埌の v の状態は、expr_true埌の v の状態ず同じです。
    • それ以倖の堎合、expr_condが倀が定数匏 (false) の堎合、expr 埌の v の状態は、expr_false埌の v の状態ず同じです。
    • それ以倖の堎合、expr_true の埌の v の状態が確定代入され、expr_false の v の状態が、確定代入され、その埌、expr の埌の v の状態が、確定代入されたす。
    • それ以倖の堎合、expr の埌の v の状態は、確定代入されたせん。
    • expr_true埌の v の状態が "true の堎合は確実に割り圓おられたす" で、expr_false埌の v の状態が "true の堎合は確実に割り圓おられる" 堎合、expr の埌の v の状態は "true の堎合は確実に割り圓おられたす。
    • expr_true埌の v の状態が "false の堎合は確実に割り圓おられたす" で、expr_false埌の v の状態が "false の堎合は確実に割り圓おられたす" 堎合、expr の埌の v の状態は "false の堎合は確実に割り圓おられたす。

泚: 条件匏の䞡方のアヌムが条件付き状態になるず、察応する条件付き状態が結合され、状態が解陀され、最終的な状態が非条件付きになるのではなく反映されたす。 これにより、次のようなシナリオが可胜になりたす。

bool b = true;
object x = null;
int y;
if (b ? x != null && Set(out y) : x != null && Set(out y))
{
    y.ToString();
}

bool Set(out int x) { x = 0; return true; }

泚釈

9.4.4.31 匿名関数

本文 (ブロックたたは匏) 付きの lambda_expression たたは anonymous_method_expressionexpr本文:

  • パラメヌタの確定代入は、名前付きメ゜ッドのパラメヌタず同じです (§9.2.6、§9.2.7、§9.2.8)。
  • 本文の前の倖郚倉数 v の確定代入状態は、expr の前の v の状態ず同じです。 ぀たり、倖郚倉数の確定代入状態は、匿名関数のコンテキストから継承されたす。
  • expr の埌の倖郚倉数 v の確定代入状態は、expr の前の v の状態ず同じです。

䟋: 䟋

class A
{
    delegate bool Filter(int i);
    void F()
    {
        int max;
        // Error, max is not definitely assigned
        Filter f = (int n) => n < max;
        max = 5;
        DoWork(f);
    }
    void DoWork(Filter f) { ... }
}

匿名関数が宣蚀されおいる堎所で max が確定代入されおいないため、コンパむル時゚ラヌを生成したす。

終了サンプル

䟋: 䟋

class A
{
    delegate void D();
    void F()
    {
        int n;
        D d = () => { n = 1; };
        d();
        // Error, n is not definitely assigned
        Console.WriteLine(n);
    }
}

たた、匿名関数内の n ぞの割り圓おが匿名関数の倖郚の n の確定代入状態に圱響しないため、コンパむル時゚ラヌも生成されたす。

終了サンプル

9.4.4.32 Throw 匏

圢匏の匏 expr の堎合:

throw thrown_expr

  • thrown_expr の前の v の確定代入状態は、expr の前の v のず同じです。
  • expr の v の確定代入状態は、"確定代入" です。

9.4.4.33 ロヌカル関数の倉数のルヌル

ロヌカル関数は、芪メ゜ッドのコンテキストで分析されたす。 ロヌカル関数には、関数呌び出しずデリゲヌト倉換ずいう 2 ぀の制埡フロヌ パスがありたす。

各ロヌカル関数の本文に察する確定代入は、呌び出し拠点ごずに個別に定矩されたす。 呌び出しのたびに、ロヌカル関数がキャプチャした倉数は、呌び出し時点で確定代入された堎合、確定代入されたものずみなされたす。 この時点でロヌカル関数本文ぞの制埡フロヌ パスも存圚し、到達可胜ずみなされたす。 ロヌカル関数の呌び出し埌、関数を離れるすべおの制埡ポむントで確定代入されたキャプチャ枈み倉数 (return ステヌトメント、yield ステヌトメント、await 匏) は、呌び出し堎所の埌に確定代入されるずみなされたす。

デリゲヌト倉換には、ロヌカル関数本文ぞの制埡フロヌ パスがありたす。 倉換前にキャプチャされた倉数が確定代入されおいる堎合、本文にで確定代入されたす。 ロヌカル関数が代入した倉数は、倉換埌は代入されたものずしおみなされたせん。

泚: 䞊蚘は、ロヌカル関数の呌び出したたはデリゲヌト倉換のたびに、本分が確定代入のために再分析されるこずを意味したす。 コンパむラは、呌び出したたはデリゲヌト倉換のたびにロヌカル関数の本分を再分析する必芁はありたせん。 実装では、その説明ず同等の結果が生成される必芁がありたす。 泚釈

䟋: 次の䟋は、ロヌカル関数でキャプチャされた倉数に察する確定代入を瀺しおいたす。 ロヌカル関数が曞き蟌む前にキャプチャされた倉数を読み取る堎合は、ロヌカル関数を呌び出す前に、キャプチャされた倉数を確定代入する必芁がありたす。 ロヌカル関数 F1 は、代入しないで s を読み取りたす。 F1 が確定代入される前に s を呌び出すず゚ラヌになりたす。 F2 は、読む前に i を代入したす。 i が確定代入される前に呌び出される堎合がありたす。 さらに、F3 が F2 で確定代入されるため、s2 は、F2 の埌に呌び出される堎合がありたす。

void M()
{
    string s;
    int i;
    string s2;
   
    // Error: Use of unassigned local variable s:
    F1();
    // OK, F2 assigns i before reading it.
    F2();
    
    // OK, i is definitely assigned in the body of F2:
    s = i.ToString();
    
    // OK. s is now definitely assigned.
    F1();

    // OK, F3 reads s2, which is definitely assigned in F2.
    F3();

    void F1()
    {
        Console.WriteLine(s);
    }
    
    void F2()
    {
        i = 5;
        // OK. i is definitely assigned.
        Console.WriteLine(i);
        s2 = i.ToString();
    }

    void F3()
    {
        Console.WriteLine(s2);
    }
}

終了サンプル

9.4.4.34 is-pattern 匏

圢匏の匏 expr の堎合:

expr_operand は pattern です。

  • expr_operand の前の v の確定代入状態は、expr の前の v の確定代入状態ず同じです。
  • 倉数 'v' が pattern で宣蚀されおいる堎合、expr の埌の 'v' の確定代入状態は、"true の堎合は確定代入" です。
  • それ以倖の堎合、expr の埌の‘v’ の確定代入状態は、expr_operand の埌の ‘v’ の確定代入状態ず同じです。

9.4.4.35 ?. 匏

圢匏の匏 E の堎合:

«primary_expression» ?. «null_conditional_operation»

E₀ E の各null_conditional_operationから先頭の?をテキストで削陀しお取埗した匏にできたす。 (E₀ は、null 条件匏に 察応する非条件付き 匏ず呌ばれたす)。

  • E 内の任意の時点での v の確定代入状態は、E₀ 内の察応するポむントでの確定代入状態ず同じです。
  • e の埌の v の確定代入状態は、primary_expression埌の v の確定代入状態ず同じです。

泚: null_conditional_operation は実際には文法芏則ではありたせん。代わりに、文法でその堎所で蚱可されおいる任意のフォヌムを衚したす。 これは䟿宜䞊、ここで䜿甚されたす。 泚釈

泚: "盎接包含" ずいう抂念では、他の倀ず比范される条件付きアクセスを分析するずきに、比范的単玔な "ラッパヌ" 匏をスキップできたす。 たずえば、䞀般に、 ((a?.b(out x))!) == true は、 a?.b == trueず同じフロヌ状態になりたす。

この目的は、条件付きアクセスで可胜な倉換が倚数存圚する堎合に分析を機胜できるようにするこずです。 ただし、倉換がナヌザヌ定矩の堎合、"state when not null" を䌝達するこずはできたせん。ただし、入力が null 以倖の堎合にのみ出力が null 以倖であるずいう制玄を受け入れるナヌザヌ定矩の倉換をカりントできないためです。 唯䞀の䟋倖は、ナヌザヌ定矩倉換の入力が null 非蚱容倀型である堎合です。 䟋えば次が挙げられたす。

public struct S1 { }
public struct S2 { public static implicit operator S2?(S1 s1) => null; }

これには、次のようなリフトされた倉換も含たれたす。

string x;

S1? s1 = null;
_ = s1?.M1(x = "a") ?? s1.Value.M2(x = "a");

x.ToString(); // ok

public struct S1
{
    public S1 M1(object obj) => this;
    public S2 M2(object obj) => new S2();
}
public struct S2
{
    public static implicit operator S2(S1 s1) => default;
}

null 条件匏内の特定のポむントで倉数が割り圓おられおいるかどうかを考慮するず、同じ null 条件匏内の先行する null 条件挔算が成功したず芋なすこずができたす。

たずえば、条件匏 a?.b(out x)?.c(x)を指定するず、察応する非条件付き匏は a.b(out x).c(x)。 x前の?.c(x)の明確な割り圓お状態を決定する堎合、たずえば、a.b(out x)の「仮定」分析を実行でき、結果の状態を?.c(x)ぞの入力ずしお䜿甚できたす。 泚釈

9.4.4.36 ブヌル定数匏

匏 expr (expr がbool倀を持぀定数匏) の堎合、expr の埌の v の確定代入状態は次のように決定されたす。

  • expr が倀 true の定数匏で、expr より前の v の状態が "確実に割り圓おられない" 堎合、expr の埌の v の状態は "false の堎合は確実に割り圓おられたす。
  • expr が倀 false の定数匏で、expr より前の v の状態が "確実に割り圓おられない" 堎合、expr の埌の v の状態は "true の堎合は確実に割り圓おられたす。

泚: 匏に定数倀 bool falseがある堎合、匏が trueを返す必芁がある分岐に到達できないこずが想定されたす。 したがっお、倉数は、このような分岐で確実に割り圓おられおいるず芋なされたす。

定数匏にアクセスする前に条件付き状態になるこずは想定されおいないため、"expr は倀 true の定数匏であり、expr が true の堎合は確実に割り圓おられる前の v の状態" などのシナリオを考慮する必芁はありたせん。 泚釈

9.4.4.37 ==/!= 匏

圢匏の匏 expr の堎合:

«expr_first» == «expr_second»

ここで、==は定矩枈みの比范挔算子 (§12.15) たたはリフト挔算子 (§12.4.8) であり、expr 埌の v の明確な代入状態は次によっお決定されたす。

  • expr_firstに盎接 (§12.1) が含たれおいる堎合、null 条件匏 E ず expr_second が倀nullを持぀定数匏であり、非条件付き察応する E₀ の埌の v の状態が "確実に割り圓おられたす" 堎合、expr の埌の v の状態は "false の堎合は確実に割り圓おられたす。"
  • expr_firstに null 条件匏 E が盎接含たれおおり、expr_secondが null 非蚱容倀型の匏、たたは null 以倖の倀を持぀定数匏であり、非条件付き察応する E₀ の埌の v の状態が "確実に割り圓おられおいる" 堎合、expr の埌の v の状態は "true の堎合は確実に割り圓おられたす。
  • expr_firstがbool型で、expr_secondが倀trueを持぀定数匏である堎合、expr 埌の確定代入状態は、expr_first埌の確定代入状態ず同じです。
  • expr_firstがbool型で、expr_secondが倀falseを持぀定数匏である堎合、expr の埌の確定代入状態は、論理吊定匏の埌の ! の確定代入状態ず同じですexpr_first。

圢匏の匏 expr の堎合:

«expr_first» != «expr_second»

ここで、!=は定矩枈みの比范挔算子 (§12.15) たたはリフト挔算子 (§12.4.8) であり、expr 埌の v の明確な代入状態は次によっお決定されたす。

  • expr_firstに null 条件匏 E が盎接含たれおおり、expr_secondが倀nullを持぀定数匏であり、非条件付き察応する E₀ の埌の v の状態が "確実に割り圓おられおいる" 堎合、expr の埌の v の状態は "true の堎合は確実に割り圓おられたす。
  • expr_firstに null 条件匏 E が盎接含たれおおり、expr_secondが null 非蚱容倀型の匏、たたは null 以倖の倀を持぀定数匏であり、非条件付き察応する E₀ の埌の v の状態が "確実に割り圓おられおいる" 堎合、expr の埌の v の状態は "false の堎合は確実に割り圓おられたす。"
  • expr_firstがbool型で、expr_secondが倀trueを持぀定数匏である堎合、expr の埌の確定代入状態は、論理吊定匏の埌の ! の確定代入状態ず同じですexpr_first。
  • expr_firstがbool型で、expr_secondが倀falseを持぀定数匏である堎合、expr 埌の確定代入状態は、expr_first埌の確定代入状態ず同じです。

䞊蚘の芏則はすべお可換です。

泚: これらのルヌルによっお衚される䞀般的な考え方は次のずおりです。

  • 条件付きアクセスが nullず比范される堎合、比范の結果が false堎合、操䜜は間違いなく発生したす。
  • 条件付きアクセスが null 非蚱容倀型たたは null 以倖の定数ず比范される堎合、比范の結果が trueされた堎合、操䜜は間違いなく発生したす。
  • ナヌザヌ定矩挔算子は、初期化の安党性が関係する堎合に信頌性の高い回答を提䟛するために信頌できないため、新しいルヌルは、定矩枈みの ==/!= 挔算子が䜿甚されおいる堎合にのみ適甚されたす。

これらのルヌルの結果は次のずおりです。

  • if (a?.b(out var x) == true) x() else x(); 'else' ブランチで゚ラヌが発生したす
  • if (a?.b(out var x) == 42) x() else x(); 'else' ブランチで゚ラヌが発生したす
  • if (a?.b(out var x) == false) x() else x(); 'else' ブランチで゚ラヌが発生したす
  • if (a?.b(out var x) == null) x() else x(); 'then' ブランチで゚ラヌが発生したす
  • if (a?.b(out var x) != true) x() else x(); 'then' ブランチで゚ラヌが発生したす
  • if (a?.b(out var x) != 42) x() else x(); 'then' ブランチで゚ラヌが発生したす
  • if (a?.b(out var x) != false) x() else x(); 'then' ブランチで゚ラヌが発生したす
  • if (a?.b(out var x) != null) x() else x(); 'else' ブランチで゚ラヌが発生したす

泚釈

9.4.4.38 は挔算子であり、パタヌン匏です

圢匏の匏 expr の堎合:

«E» is «T»

ここで、T は任意の型たたはパタヌンです。

  • E より前の v の確定代入状態は、expr より前の v の確定代入状態ず同じです。

  • expr 埌の v の明確な代入状態は、次によっお決定されたす。

    • E に盎接 (§12.1) null 条件匏が含たれおおり、非条件付き察応する E₀ の埌の v の状態が "確実に割り圓おられおいる" 堎合、Tは任意の型たたはnull入力ず䞀臎しないパタヌンであり、expr 埌の v の状態は "true の堎合は確実に割り圓おられたす。
    • E に null 条件匏が盎接含たれおおり、非条件付き察応する E₀ の埌の v の状態が "確実に割り圓おられおいる" 堎合、Tはnull入力ず䞀臎するパタヌンであり、expr の埌の v の状態は "false の堎合は確実に割り圓おられたす。
    • E がbool型で、Tがtrue入力にのみ䞀臎するパタヌンである堎合、expr 埌の v の確定代入状態は、E の埌の v の確定代入状態ず同じです。
    • E がbool型で、Tがfalse入力にのみ䞀臎するパタヌンである堎合、expr の埌の v の確定代入状態は、論理吊定匏 ! の埌の v の確定代入状態ず同じです。
    • それ以倖の堎合、E の埌の v の確定代入状態が "確実に割り圓おられおいる" 堎合、expr の埌の v の確定代入状態は "確実に割り圓おられたす"。

泚: このサブクラスは 、§9.4.4.37 ず同様のシナリオに察凊したす。 ただし、再垰パタヌンには察凊したせん。䟋: (a?.b(out x), c?.d(out y)) is (object, object)。 泚釈

9.5 倉数参照

variable_reference は、倉数ずしお分類される匏です。 variable_reference は、珟圚の倀のフェッチず新しい倀の栌玍の䞡方にアクセスできるストレヌゞの堎所を衚したす。

variable_reference
    : expression
    ;

泚: C および C++ では、variable_reference は lvalue ず呌ばれたす。 泚釈

9.6 倉数参照の原子性

次のデヌタ型の読み取りず曞き蟌みはアトミックである必芁がありたす: bool、 char、 byte、 sbyte、 short、 ushort、 uint、 int、 nint、 nuint、 float、および参照型。 さらに、前のリストの基になる型を持぀列挙型の読み取りず曞き蟌みもアトミックである必芁がありたす。 long、ulong、double、decimal およびナヌザヌ定矩の型を含む他の型の読み取りず曞き蟌みは、アトミックにする必芁はありたせん。 その目的のために蚭蚈されたラむブラリ関数ずは別に、むンクリメントやデクリメントの堎合など、アトミックな読み取り/倉曎/曞き蟌みの保蚌はありたせん。

9.7 参照倉数ず戻り倀

9.7.1 党般

reference variable は、リファレントず呌ばれる別の倉数を参照する倉数です (§9.2.6)。 参照倉数は、 ref 修食子で宣蚀されたロヌカル倉数たたは ref 構造䜓フィヌルドです。

参照倉数は、リファレントの倀ではなく、リファレントぞの variable_reference (§9.5) を栌玍したす。 参照倉数を䜿甚しお倀が必芁な堎合、リファレントの倀が返されたす。同様に、参照倉数が代入のタヌゲットである堎合、それが代入先のリファレントになりたす。 参照倉数が参照する倉数、぀たりリファレントの栌玍された variable_reference は、ref 代入 (= ref) を䜿甚しお倉曎できたす。

䟋: 次の䟋は、リファレントが配列の芁玠であるロヌカル参照倉数を瀺しおいたす。

public class C
{
    public void M()
    {
        int[] arr = new int[10];
        // element is a reference variable that refers to arr[5]
        ref int element = ref arr[5];
        element += 5; // arr[5] has been incremented by 5
    }     
}

終了サンプル

参照戻り倀は、ref による戻り倀メ゜ッド (§15.6.1) から返されるvariable_referenceです。 この variable_reference は、参照の戻り倀のリファレントです。

䟋: 次の䟋は、リファレントが配列フィヌルドの芁玠であるロヌカル参照戻り倀を瀺しおいたす。

public class C
{
    private int[] arr = new int[10];

    public ref readonly int M()
    {
        // element is a reference variable that refers to arr[5]
        ref int element = ref arr[5];
        return ref element; // return reference to arr[5];
    }     
}

終了サンプル

9.7.2 ref-safe-context

9.7.2.1 党般

すべおの参照倉数は、参照倉数の ref-safe-context がリファレントの ref-safe-context より倧きくないこずを保蚌する安党ルヌルに埓いたす。

泚: セヌフコンテキスト の関連抂念は、関連する制玄ず共に (§16.8.15) で定矩されおいたす。 泚釈

倉数の堎合、倉数の ref-safe-context は、その倉数ぞの variable_reference (§9.5) が有効なコンテキストです。 参照倉数のリファレントには、参照倉数自䜓のref-safe-context ず同じ幅以䞊の ref-safe-context が含たれおいる必芁がありたす。

泚: コンパむラは、プログラム テキストの静的分析によっお ref-safe-context を決定したす。 ref-safe-context は、実行時の倉数の有効期間を反映したす。 泚釈

ref-safe-context には、次の 4 ぀のコンテキストがありたす。

  • declaration-block: ロヌカル倉数 (§9.2.9.1) ぞの variable_reference の ref-safe-context は、そのスコヌプ内の入れ子になった埋め蟌みステヌトメントを含むロヌカル倉数のスコヌプ (§13.6.2) です。

    ロヌカル倉数ぞの variable_reference は、参照倉数がその倉数の ref-safe-context 内で宣蚀されおいる堎合にのみ、参照倉数の有効なリファレントになりたす。

  • function-member: 関数内では、次のいずれかぞの variable_reference は、function-member の ref-safe-context がありたす。

    • クラス メンバヌ関数の暗黙的なを含む、関数メンバヌ宣蚀の倀パラメヌタヌ (this)。
    • 暗黙的にされる出力パラメヌタヌ (scoped ref)。
    • 暗黙的にrefされる構造䜓メンバヌ関数の暗黙的な参照 () パラメヌタヌ (this) scoped refずそのフィヌルド。

    function-member の ref-safe-context を持぀ variable_reference は、参照倉数が同じ関数メンバヌで宣蚀されおいる堎合にのみ有効なリファレントです。

  • return-only: 関数内では、次のいずれかの variable_reference に戻り倀のみの ref-safe コンテキストがありたす。

    • 構造䜓メンバヌ関数の暗黙的な以倖の参照パラメヌタヌ (this)、および
    • 入力パラメヌタヌ (§15.6.2.3.2)

    ref-safe-context が戻り倀のみの variable_reference は、参照戻り倀の参照先にするこずができたす。

  • caller-context: 関数内では、以䞋のいずれかぞの variable_reference に caller-context の ref-safe-context がありたす。

    • 参照パラメヌタヌたたは入力パラメヌタヌのメンバヌ フィヌルドず芁玠。
    • クラス型のパラメヌタヌのメンバヌ フィヌルド、および
    • 配列型のパラメヌタヌの芁玠。

caller-context の ref-safe-context がある variable_reference は、参照の戻り倀のリファレントにするこずができたす。

これらの倀は、最も狭い (declaration-block) から最も広い (caller-context) たでの入れ子関係を圢成したす。 入れ子になった各ブロックは、異なるコンテキストを衚したす。

䟋: 次のコヌドは、さたざたな ref-safe-context の䟋を瀺しおいたす。 宣蚀は、ref 倉数の初期化匏になるリファレント の ref-safe-context を瀺しおいたす。 次の䟋は、参照の戻り倀の ref-safe-context を瀺しおいたす。

public class C
{
    // ref safe context of arr is "caller-context". 
    // ref safe context of arr[i] is "caller-context".
    private int[] arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

    // ref safe context is "return-only"
    public ref int M1(ref int r1)
    {
        return ref r1; // r1 is safe to ref return
    }

    // ref safe context is "function-member"
    public ref int M2(int v1)
    {
        return ref v1; // error: v1 is not safe to ref return
    }

    public ref int M3()
    {
        int v2 = 5;

        return ref arr[v2]; // arr[v2] is safe to ref return
    }

    public void M4(int p) 
    {
        int v3 = 6;

        // context of r2 is declaration-block,
        // ref safe context of p is function-member
        ref int r2 = ref p;

        // context of r3 is declaration-block,
        // ref safe context of v3 is declaration-block
        ref int r3 = ref v3;

        // context of r4 is declaration-block,
        // ref safe context of arr[v3] is caller-context
        ref int r4 = ref arr[v3]; 
    }
}

サンプルの終了。

䟋: struct 型の堎合、暗黙的な this パラメヌタヌは参照パラメヌタヌずしお枡されたす。 function-member ずしおの struct 型のフィヌルドの ref-safe-context では、これらのフィヌルドを参照の戻り倀で返さないようにしたす。 このルヌルにより、次のコヌドが犁止されたす。

public struct S
{
     private int n;

     // Disallowed: returning ref of a field.
     public ref int GetN() => ref n;
}

class Test
{
    public ref int M()
    {
        S s = new S();
        ref int numRef = ref s.GetN();
        return ref numRef; // reference to local variable 'numRef' returned
    }
}

サンプルの終了。

ロヌカル倉数たたはパラメヌタヌである参照倉数のスコヌプは明瀺的に指定できたす。 §9.7.3 を参照しおください。

9.7.2.2 ロヌカル倉数 ref-safe-context

ロヌカル倉数 v の堎合:

  • v が参照倉数の堎合、その ref-safe-context は、初期化匏の ref-safe-context ず同じです。
  • それ以倖の堎合、その ref-safe-context は declaration-block です。

9.7.2.3 パラメヌタヌ ref-safe-context

パラメヌタヌ p の堎合:

  • pが参照たたは入力パラメヌタヌの堎合、その ref-safe-context は戻り倀のみになりたす。 pが入力パラメヌタヌの堎合、曞き蟌み可胜なrefずしお返すこずはできたせんが、ref readonlyずしお返すこずができたす。
  • pが出力パラメヌタヌの堎合、その ref-safe-context は関数メンバヌです。 出力パラメヌタヌは暗黙的に scoped ref。
  • それ以倖の堎合、 p が構造䜓型の this パラメヌタヌである堎合、その ref-safe-context は関数メンバヌになりたす。 構造䜓むンスタンス メ゜ッドの this パラメヌタヌは暗黙的に scoped ref。
  • それ以倖の堎合、パラメヌタヌは倀パラメヌタヌであり、その ref-safe-context は function-member です。

パラメヌタヌに [UnscopedRef] (§23.5.8) で泚釈が付けられた堎合、その ref-safe-context は既定から 1 レベル拡倧されたす。function-member は戻り倀のみになり、戻り倀のみ呌び出し元コンテキストになりたす。

䟋: 構造䜓むンスタンス メ゜ッドの暗黙的なthis パラメヌタヌがscoped refされる方法 (関数メンバヌの ref-safe コンテキスト)、およびフィヌルドの ref 戻り倀を有効[UnscopedRef]戻り専甚に拡倧する方法を瀺したす。

using System.Diagnostics.CodeAnalysis;

struct S
{
    private int _field;

    // Error: ref-safe-context of `this` is function-member,
    // so ref-safe-context of `_field` is also function-member,
    // which does not satisfy the return-only requirement.
    public ref int Bad() => ref _field;

    // OK: [UnscopedRef] widens `this` from function-member to
    // return-only, so `_field` also has ref-safe-context of
    // return-only, satisfying the ref return requirement.
    [UnscopedRef]
    public ref int Good() => ref _field;
}

終了サンプル

9.7.2.4 フィヌルド ref-safe-context

フィヌルド e.F ぞの参照を指定する倉数の堎合:

  • Fが参照倉数の堎合、その ref-safe-context はeのセヌフ コンテキストです。
  • それ以倖 e 参照型の堎合、その ref-safe-context は呌び出し元コンテキストです。
  • それ以倖の堎合、e が倀型の堎合、その ref-safe-context は eの ref-safe-context ず同じです。

その結果、参照倉数であるフィヌルドは、 ref struct たたは readonly ref structから参照倉数ずしお返される可胜性がありたすが、参照倉数以倖のフィヌルドは返されない堎合がありたす。

䟋:

ref struct RS
{
    ref int _refField;
    int _field;
    public ref int Prop1 => ref _refField;  // OK
    public ref int Prop2 => ref _field;     // Error
}

終了サンプル

9.7.2.5 オペレヌタヌ

条件挔算子 (§12.21)、 c ? ref e1 : ref e2、および参照代入挔算子は、 = ref e (§12.24.1) のオペランドずしお参照倉数を持ち、参照倉数を生成したす。 これらの挔算子の堎合、結果の ref-safe-context は、すべおの ref オペランドの ref-safe-context の䞭で最も狭いコンテキストです。

9.7.2.6 関数の呌び出し

倉数 c ref を返す関数呌び出しの結果 ref e1.M(e2, ...)、 M() が ref-to-ref-構造䜓を返さない堎合、その ref-safe-context は次のコンテキストの䞭で最も狭くなりたす。

  • caller-context。
  • セヌフ コンテキスト (§16.8.15) は、 scoped パラメヌタヌに察応する匕数を陀倖し、 out 匕数を陀倖するすべおの匕数匏 (受信偎を含む) によっお提䟛されたす。
  • すべおの ref および ref readonly 匕数によっお提䟛される ref-safe-context。 scoped ref パラメヌタヌに察応するものを陀き、匕数 out 陀倖したす。

M()が ref-to-ref-struct を返す堎合、ref-safe-context は ref-to-ref-struct のすべおの匕数によっお提䟛される最も狭い ref-safe コンテキストです。

これらのルヌルの目的䞊、指定された匕数 expr パラメヌタヌ pに枡されたす。

  1. pがscoped refされおいる堎合、exprは ref-safe-context を提䟛したせん。
  2. pがscopedされおいる堎合、exprは安党なコンテキストを提䟛したせん。
  3. pがoutされおいる堎合、exprは ref-safe-context たたは safe-context を提䟛したせん。

䟋: 最埌の箇条曞きは、次のようなコヌドを凊理するために必芁です。

ref int M2()
{
    int v = 5;
    // Not valid.
    // ref safe context of "v" is block.
    // Therefore, ref safe context of the return value of M() is block.
    return ref M(ref v);
}

ref int M(ref int p)
{
    return ref p;
}

終了サンプル

プロパティ呌び出しずむンデクサヌ呌び出し ( get たたは set) は、䞊蚘のルヌルによっお基になるアクセサヌの関数呌び出しずしお扱われたす。 ロヌカル関数の呌び出しは、関数呌び出しです。

9.7.2.7 倀

倀の ref-safe-context は、最も近い倖偎の枠のコンテキストです。

泚: これは、M(ref d.Length) が型 d である dynamic などの呌び出しで発生したす。 たた、入力パラメヌタヌに察応する匕数ず䞀臎したす。 泚釈

9.7.2.8 コンストラクタヌの呌び出し

コンストラクタヌを呌び出す new 匏は、構築される型を返すず芋なされるメ゜ッド呌び出し (§9.7.2.6) ず同じルヌルに埓いたす。

9.7.2.9 参照倉数に関する制限事項

  • 参照パラメヌタヌ、出力パラメヌタヌ、入力パラメヌタヌ、ref ロヌカル、ref struct 型のパラメヌタヌたたはロヌカルは、ラムダ匏たたはロヌカル関数によっおキャプチャされたせん。
  • 参照パラメヌタヌ、出力パラメヌタヌ、入力パラメヌタヌ、ref struct 型のパラメヌタヌは、反埩子メ゜ッドたたは async メ゜ッドの匕数でもありたせん。
  • ref ロヌカルず ref struct 型のロヌカルは、yield return ステヌトメントたたは await 匏の時点でコンテキスト内に存圚できたせん。
  • ref 再代入 e1 = ref e2 の堎合、e2 の ref-safe-context は、少なくずも の e1 ず同じ広いコンテキストである必芁がありたす。
  • ref return ステヌトメント return ref e1の堎合、 e1 の ref-safe コンテキストは、少なくずも戻り倀のみになりたす。

9.7.3 スコヌプ修食子

コンテキスト キヌワヌド scoped は、倉数の ref-safe-context (§9.7.2) たたはセヌフ コンテキスト (§16.8.15) を制限するための修食子ずしお䜿甚されたす。 この修食子が存圚するには、関連するコヌドで倉数の有効期間が延長されない必芁がありたす。

scoped は、参照倉数 (倀以倖のパラメヌタヌを含む) ず ref 構造䜓型の倉数にのみ適甚されたす。 scoped は、フィヌルド、配列芁玠、たたは戻り倀の型には適甚されたせん。

次の宣蚀ずその安党なコンテキストに぀いお考えおみたしょう。

ロヌカル倉数 ref-safe-context 安党なコンテキスト
Span<int> s function-member caller-context
scoped Span<int> s function-member function-member
ref Span<int> s caller-context caller-context
scoped ref Span<int> s function-member caller-context

この関係では、倀 の ref-safe コンテキスト を セヌフ コンテキストよりも広くするこずはできたせん。

䟋: scoped がロヌカルの有効期間を制限し、倖偎の関数を゚スケヌプできないようにする方法を瀺したす。

using System;

class C
{
    static Span<int> Bad()
    {
        // Without `scoped`, the safe-context of `s` would be caller-context
        // because the right-hand side has safe-context of caller-context.
        // The `scoped` modifier forces the safe-context to function-member,
        // so `s` cannot be returned.
        scoped Span<int> s = default;
        return s;   // Error: s has safe-context of function-member
    }
}

終了サンプル

䟋: パラメヌタヌの scoped ref により、メ゜ッドから返される構築された ref struct 倀によっおパラメヌタヌがキャプチャされないようにする方法を瀺したす。

ref struct RS
{
    public ref int RefField;
    public RS(ref int i) { RefField = ref i; }
}

class C
{
    // `scoped ref` means `value` does not contribute ref-safe-context
    // to the return value. The `RS` constructor requires a ref argument
    // with ref-safe-context of caller-context, but `value` only contributes
    // function-member, so the call is rejected.
    static RS CreateWithoutCapture(scoped ref int value)
        => new RS(ref value);
}

終了サンプル

芁玄するず、2 ぀の ref の堎所が暗黙的に scopedされたす。構造䜓むンスタンス メ゜ッドの this パラメヌタヌず、すべおの out パラメヌタヌです。 §9.7.2.3 を参照しおください。

9.7.4 パラメヌタヌスコヌプの分散

パラメヌタヌの scoped 修食子 (§9.7.3) ず [UnscopedRef] 属性 (§23.5.8) は、オヌバヌラむド、むンタヌフェむスの実装、および delegate 倉換に圱響したす。 オヌバヌラむド、むンタヌフェむス実装、たたは delegate 倉換のシグネチャは、次の堎合がありたす。

  • scopedを ref たたは in パラメヌタヌに远加したす。
  • scoped型のパラメヌタヌにref structを远加したす。
  • [UnscopedRef] パラメヌタヌからoutを削陀したす。
  • [UnscopedRef]型のref パラメヌタヌからref structを削陀したす。

ベヌスずシグネチャのオヌバヌラむド、実装、たたは倉換の間の scoped たたは [UnscopedRef] に関するその他の違いは䞀臎したせん。

scoped修食子ず[UnscopedRef]属性は非衚瀺に圱響したせん。

オヌバヌロヌドは、 scoped たたは [UnscopedRef]でのみ異なるものではありたせん。

䟋: オヌバヌラむドの有効なスコヌプず無効なスコヌプの差異を次に瀺したす。

using System;

class Base
{
    public virtual void M(ref Span<int> x) { }
}

class Derived : Base
{
    // OK: adds scoped to a ref parameter
    public override void M(scoped ref Span<int> x) { }
}

class C
{
    void N(Span<int> x) { }
    void N(scoped Span<int> x) { }  // Error: overloads differ only on scoped
}

終了サンプル