静的メンバ
インスタンスを持たないメンバ
これまでのフィールドやメソッドといったメンバは、それぞれがインスタンスに固有でした。従って、各メンバにアクセスするにはインスタンスが必要であり、インスタンスごとに専用の記憶領域を保持しています。このような性質のメンバ(これまでのフィールド、メソッド、コンストラクタ、プロパティ)のことをインスタンスメンバ(instance member)とも呼びます。
一方で、クラスのデータを 全てのインスタンスで共有したい場合もあるでしょう。または、単一の値しか持たない性質のデータをインスタンスごとに持たせることも メモリの無駄な消費につながります。 このような、インスタンスを必要としない操作には静的メンバ(static member)を用います。静的メンバは、インスタンスではなくクラス型に直接関連付けられます。
静的メンバを宣言するには、メンバ宣言に static 修飾子(static modifier)を指定します。私たちは、すでに static 修飾子による静的メンバを宣言しています。これまで何度も使ってきた Main() メソッドです。アプリケーションの起動時にはインスタンスが不要であり Main() メソッドはインスタンスではなく、宣言されたクラスに所属します。
class A { public static int Value { get; set; } public static void M() { } }
上のコードは静的プロパティと静的メソッドを宣言しています。これらのメンバ宣言には public アクセス修飾子と static 修飾子の 2 つの修飾子を指定していますが、修飾子の出現順序は問われません。public と static が逆でも問題はありませんが、経験的に多くの開発者はアクセス修飾子を先に記述します。公式ドキュメントに掲載されているコードもアクセス修飾子を先に書いています。
静的メンバは実行単位に 1 つしか実体が存在しません。メンバアクセスには、インスタンスではなく静的メンバを持つ型(クラス名)を用います。上記の Value プロパティや M() メソッドを呼び出すには、以下のように記述します。
A.Value = 10; A.M();
静的メンバのアクセスにインスタンスを用いるとコンパイルエラーとなります。
class MagicalGirl { public static int RepeatCount { get; private set; } public void BackToPast() { RepeatCount += 1; System.Console.WriteLine("君の望みはエントロピーを凌駕した"); } } class Test { public static void Main(string[] args) { MagicalGirl homura = new MagicalGirl(); System.Console.WriteLine(MagicalGirl.RepeatCount + "回目 彼女との出会いをやり直したい"); homura.BackToPast(); System.Console.WriteLine(MagicalGirl.RepeatCount + "回目 みんなキュゥべえに騙されてる!"); homura.BackToPast(); System.Console.WriteLine(MagicalGirl.RepeatCount + "回目 必ずあなたを守って見せる"); homura.BackToPast(); } }
コード1の RepeatCount プロパティは読み取り専用の静的メンバです。外部から RepeatCount プロパティにアクセスするには MagicalGirl.RepeatCount と記述します。インスタンスではなくクラス名からメンバアクセスしています。静的メンバである RepeatCount プロパティは単一の値であり、アクセスにインスタンスは不要です。
インスタンスメンバである BackToPast() メソッドからは、クラス名を省略して RepeatCount プロパティにアクセスし、値をインクリメントしています。静的メンバを含むクラス内のコードからは、インスタンスメンバと同様にメンバ名だけで静的メンバにアクセスできます。
このように、静的メンバはインスタンスではなくクラスに結び付けらます。静的メソッドはインスタンスメソッドと異なり、インスタンス無しで動作します。ただし、静的メンバはインスタンスを持たないため、静的メンバからインスタンスメンバにアクセスするには、同じクラスであってもオブジェクトが必要になります。静的なメンバは this アクセスができません。
class A { public int Value { get; set; } public static void M() { Value = 10; //エラー } }
これは、静的な M() メソッドからインスタンスメンバである Value プロパティにアクセスしようとしていますが、静的メンバは this アクセスを持たないためエラーとなります。