C#のメンバー変数(フィールド)とローカル変数について

メンバー変数とローカル変数の概要

メンバー変数(フィールドとも呼ばれる)

  • class直下で宣言される変数
  • 構文は修飾子 型名 変数名
  • 自動で初期化される(値を代入しなくても良い)
  • varは使えない

ローカル変数

  • メソッド配下で宣言される変数
  • 構文は型名 変数名
  • 自動で初期化されない(値を代入する必要がある)
  • varが使える
class Sample
{
    public int Age; // メンバー変数
    
    public void A()
    { 
        int test = 1; // ローカル変数
    }
}

初期化について

メンバー変数が自動で初期化される理由とローカル変数が自動で初期化されない理由について解説します。

メンバー変数が自動で初期化される裏付けとして以下のコードを実行してみてください。
何が出力されるでしょうか?

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var val = new Sample();
            Console.WriteLine(val.Age); // 何が出力されるでしょうか?
        }
    }
    class Sample
    {
        public int Age;

        public void A()
        { 
            int test = 1;
        }
    }
}

答えは「0」が出力されます。
このことからメンバー変数に関しては値を代入しなくてもC#が自動で初期化してくれていることが分かります。

続いてローカル変数について見ていきましょう。
Aメソッドを以下のように書くとコンパイルエラーが発生します。
これはtest変数を初期化せずに使用してるからです。このことからローカル変数に関しては自動で値を初期化してくれないことが分かります。

コンパイルを通すにはint test = 1;のように初期化してやる必要があります。

public void A()
{ 
    int test ; // int test = 1;だとコンパイルが通る
    Console.WriteLine(test);
}

では何故メンバー変数とローカル変数でこのような違いがあるのでしょうか?
※ここからは私の推測です
まず、値を自動で初期化するにはCPUのリソースを割く必要があり少し手間です。(できればプログラマに初期化してほしい)

ローカル変数は変数が宣言された時点でメソッド内で確実に使われます。
この時に、ローカル変数にどんな値が入るかC#には判断できないため、初期化する値はプログラマに委ねる必要があります。

一方フィールドはインスタンスを生成して初期化することができますが、処理によっては使用されないフィールドがある場合も考えられるため、取り敢えずC#の親切心で値を自動で初期化してくれてると推測してます。

フィールドでvarが使用できない理由

varとは?
varを使用することで、明示的に型を指定しなくてもコンパイル時に初期値から型を推測してくれます。
例:var str = “”;とすると初期値を見て、コンパイラがstr変数の型をstring型だと判断してくれる

以下のコードを見て分かるようにフィールドにvarを指定するとコンパイルエラーになります。

C#の仕様としてvarはローカル変数でしか指定できないようになってます。
なぜこのような仕様になってるのか私の推測を書きます。

ローカル変数はメソッド内で使用されるため初期値が設定されている可能性が高い(そもそも初期値を指定しないとエラーになる)
初期値を設定しないとコンパイルが通らないようになってるのでローカル変数ではvarが使用可能

フィールドでは初期値を指定しなくてもコンパイルは通る
→初期値がない場合もあるためvarは使用できない設計になっている

因みにローカル変数であってもvar test2;のように初期値が設定されてない場合はコンパイルエラーとなります。(初期値がないためコンパイラが型を判断できない)

class Sample
{
    public var Age; // コンテキスト キーワード 'var' は、ローカル変数宣言内またはスクリプト コード内でのみ有効ですCS0825
    // public var Age = "";にしてもコンパイルエラーとなる
    
    public void A()
    { 
        var test = 1; // コンパイル通る
        var test2; // 初期値が指定されてないためコンパイルエラー
    }
}

補足

静的フィールドとインスタンスフィールド

フィールドには静的フィールドとインスタンスフィールドというものがあります。

インスタンスフィールドとはこれまで紹介したpublic int Age;のようなフィールドです。
対して静的フィールドとはpublic static int Age;のようなstaticキーワードが付与されてるフィールドのことを指します。

違いとして、インスタンスフィールドはインスタンス名.Ageのようにインスタンス経由でアクセスするのに対して、静的フィールドはクラス名.Ageのようにしてアクセスします。
静的フィールドに対してインスタンス名.Ageでアクセスしようとするとエラーになります。

ここからは個人的メモを含んだ考察なので読み飛ばしていただいて構いません。

静的フィールド:存在しているメモリのアドレスが決まってるため、静的フィールドのアドレスを指定してアクセスする必要がある。
インスタンス生成でメモリを確保して静的フィールドにアクセス→静的フィールドのアドレスは決まってるので見当違いのアドレスに対してアクセスすることになるためエラーになる。

コメント

Verified by MonsterInsights
タイトルとURLをコピーしました