入れ子コードブロックとスコープ

この講義の内容は以前のレッスンでも触れていますが、今回はメモリ上のデータ保存の仕組みを通して改めて理解を深めていきます。

本チュートリアルはfoxdevelop.comより公開されています。転載する際は出典を明記してください。

メソッド本体内に別のコードブロックを入れ子にできます。

class Program
{
    static void Main()
    {
        int age = 19;
        {
            int one = 23;
        }
    }
}
Code language: C# (cs)

コードブロックの数に制限はありません。順に記述することも、複数段階で入れ子にすることも可能で、階層の上限は存在しません。

class Program
{
    static void Main()
    {
        int age = 19;
        {
            int one = 23;
            {
                int two = 45;
                {
                    int three = 56;
                }
            }
        }
    }
}Code language: C# (cs)

注意点として、入れ子内部ブロックの上に書かれた int xxxx = xxx; は、ブロックと並列の文となります。

例えば int age = 19; と、その下の入れ子コードブロックは並列する二つの文です。この全体をメソッド本体と勘違いしないでください。


ライフサイクル

例を見てみましょう

    static void Main()
    {
        int a = 10;
        {
            int b = 20;
        }
    }Code language: C# (cs)

この例にはローカル変数が二つ存在します。外側の変数aはMain関数の外側スコープ、bは内側の入れ子コードブロックに属します。

実行手順を追いながら、スタックメモリへの格納動作を確認します。

手順1:int a = 10; のみ実行。スタック上にa領域が確保され、値10が代入されます。

手順2:内側ブロックへ進み int b = 20; を実行。スタックにbが追加され、スタックは上からb、aの順に並びます。

手順3:内側コードブロックの実行が終了。bがスタックから取り除かれ、スタックにはaだけ残ります。

手順4:Mainメソッドの実行完了。aがスタックから取り除かれ、プログラム内の変数はすべて破棄され処理が終了します。

まとめ

入れ子ブロック内で宣言した変数は、宣言箇所から、属するコードブロックが終了するまで有効です。

入れ子ブロックの実行が終わると、ブロック内のすべてのローカル変数はスタックから削除され破棄されます。

メソッド本体自体も大きな一つのコードブロックと考えられます。


スコープ

既存変数のスコープが有効な間は、何段階深く入れ子にしても同名のローカル変数を新たに宣言できません。

例を確認します

    static void Main()
    {
        int a = 10;
        {
            int a = 20;
        }
    }Code language: C# (cs)

上記のコードでは、内側入れ子ブロックの変数aが外側のaと同名となるためエラーが発生し、コンパイルに失敗します。

理由:int a = 10; のスコープは自身を囲む波括弧内全体です。このスコープ内に同名変数を定義することは許可されません。int a = 20; は入れ子内部に記述されていても、外側の変数aのスコープ範囲内にあるため名称重複と判定されます。コンパイラが重複宣言を検知し、赤い波線エラーとして表示します。

二つ目の変数aの型を変更した場合でも同様に禁止されます。

同一スコープ内の変数名は一意である必要があり、変数の型は関係ありません。

画像の通り、外側変数aのスコープは黄色、内側aのスコープは緑色で示されています。外側スコープが内側領域を完全に包含しているため衝突が起きます。

解決策は内側の変数aの名前を別のものに変更することです。

別の例を見てみましょう

このように記述した場合、名称衝突は発生するでしょうか?

class Program
{
    static void Main()
    {
        int a = 10;

        {
            double b = 20;
        }

        {
            double b = 30;
        }

    }
}Code language: C# (cs)

答え:発生しません。変数bが二つ存在しますが、それぞれのスコープが重ならないためエラーにならないのです。上段のbは自身のコードブロック内、下段のbも自身のブロック内に閉じており干渉しないため正常にコンパイルできます。図を参照してください。

図には二つの変数bのスコープが色分けで示されています。読者の皆さんもこれで理解できたかと思います。

入れ子コードブロックとスコープ

Previous:

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です