変数のスコープ

変数の有効範囲

変数は必要に応じて宣言して使用しますが、プログラムのどこからでもその変数を使用できるわけではなく「その変数にアクセスできる範囲」が存在します。
これを変数のスコープと言います。


static void Main(string[] args)
{
    int numM1 = 1;

    Console.WriteLine(numM1);

    {
        int numM2 = 2;
        Console.WriteLine(numM2);

        //変数numM2の有効範囲ここまで
    }

    Console.WriteLine(numM1);

    Func(3);

    for(int x = 0; x < 3; x++)
    {
        Console.WriteLine(x);
    } //変数xの有効範囲はfor文終了まで

    Console.ReadLine();

    //変数numM1の有効範囲ここまで
}

static void Func(int arg)
{
    int numF1 = 4;
    {
        int numF2 = arg + numF1;
        Console.WriteLine(numF2);

        //変数numF2の有効範囲ここまで
    }

    //変数numF1、引数argの有効範囲ここまで
}

変数は基本的に宣言されたブロック内でのみ有効です。
({}記号で囲われた範囲がブロック)
ただし、同じブロック内でも変数を宣言するよりも前の行ではその変数は使用できません。

ブロックはメソッドの定義のほかif文やfor文などで「複数行をまとめる」場合に用いられます
それ以外にもメソッド内にさらにブロックを記述して複数の行をまとめることができます。
(7~12行目)
このブロック内で変数を宣言した場合、その変数の有効範囲はそのブロックを抜けるまでとなります。

メソッドの引数は文法的にブロックの外に記述されますが、これは例外的にそのメソッドのブロック内で有効です。

for文の初期化式で宣言された変数は、そのfor文のブロック内で使用できます。
これも文法的にブロックの外に記述されますが、続くブロック内で使用できる例外です。
この変数はfor文以外からは使用できません。

ブロックの外と内での同名変数の禁止

入れ子にされたブロックの外ブロックと内ブロックとで、同じ名前の変数を同時に使用することはできません。


static void Main(string[] args)
{
    int num = 0;
    {
        int num = 1; //エラー
    }
}

変数の宣言よりも前の行の入れ子ブロック内に同名変数があってもエラーになります。


static void Main(string[] args)
{
    {
        int num = 0; //エラー
    }
    int num = 1;
}

以下のように、ブロックがそれぞれ独立しているならば同名変数を使用できます。


static void Main(string[] args)
{
    {
        int num = 0;
    }
    {
        int num = 1;
    }
}

ローカル変数とメンバー変数(フィールド)

あるメソッド(関数)内で宣言された変数をローカル変数といいます。
ローカル変数は、そのメソッド内でのみ使用可能な変数です。
今まで使用してきた変数はすべてローカル変数です。

ローカル変数は宣言したメソッドの外側からアクセスすることはできません。
ローカル変数の値を別のメソッドで使用したい場合は、メソッドの引数と戻り値を利用してデータをやり取りするのが通常の方法です。


static void Main(string[] args)
{
    int num = 10;

    num = Func(num);
    Console.WriteLine(num);
    Console.ReadLine();
}

static int Func(int x)
{
    return x * 2;
}

それ以外に、メンバー変数として宣言する方法もあります。
(メンバー変数はフィールドとも言います)
メンバー変数はメソッドの外側で定義される変数です。


class Program
{
    //メンバー変数(フィールド)
    static int m_num;

    static void Main(string[] args)
    {
        //メンバー変数m_numはどこからでもアクセス可能
        m_num = 10;

        Func();
        
        Console.WriteLine(m_num);
        Console.ReadLine();
    }

    static void Func()
    {
		//メンバー変数m_numはどこからでもアクセス可能
        m_num *= 2;
    }
}
20

Mainメソッドや自作メソッドは、「class Program」というブロックの中に定義されます。
メンバー変数はこれらのメソッドと同じ階層に記述します。
メンバー変数は「class Program」内にあるメソッドから共通して使用できる変数となります。

「Program」の名称は変更可能です。

メソッドの定義と同じように、メンバー変数にはstaticキーワードを使用します。
これは必須ではないのですが、staticなメソッドからアクセスする場合には付ける必要があります。
(Mainメソッドはstatic)

このメンバー変数m_numは、Mainメソッドからも自作メソッドFuncからも読み書きができる変数となります。
(9行目、20行目)

このあたりはクラスの項で改めて説明します。