読者です 読者をやめる 読者になる 読者になる

プログラミングとかブログ

Unity/C#/SRPGStudio/RPGツクールMVの情報とかその他気になったことを調べて書きます。

staticメソッド内でstaticでないメンバを参照できない理由

C#

11/10 間違っちゃいないけど正確でもなかったので書き直し

Mainメソッドなどstaticメソッド内でstaticでないメンバーを扱おうとすると以下のエラーが出ます。
「静的でないフィールド、メソッド、またはプロパティ 'xxxxxx' で、オブジェクト参照が必要です。」
どうしてこのエラーが出るのでしょうか。
下記コードを例にして説明します。

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            Test.StaticMethod();
        }
    }

    class Test
    {
        object obj;

        public static void StaticMethod()
        {
            Console.WriteLine(obj);//コンパイルエラーになる
            return;
        }
    }
}

クラス内のメンバーはクラスのインスタンスを生成して初めて使用可能(メモリ展開される)となります。
しかし上記例のStaticMethodはstaticなメソッドなので、インスタンス化せず使用できます。(メモリが最初から確保されている)
ところが、上記例のようにそのメソッド内にインスタンス化しなければ使えない変数objが含まれていると、メソッドを呼び出した際に、使用不可能な(メモリ上に存在しない)変数objにアクセスすることになり、正常な処理ができなくなります。
これを防ぐためにstaticメソッド内ではstaticでないメンバーを扱えないようにしているのだと思われます。

なお、以下のようにstaticメソッド内でインスタンス化すれば普通に使えます。

  class Test
    {
        object obj;

        public static void StaticMethod()
        {
            var t = new Test(); 
            Console.WriteLine(t.obj);//コンパイルエラーにならない
            return;
        }
    }


以下修正前


Mainメソッドなどstaticメソッド内でstaticでないメンバーを扱おうとすると以下のエラーが出ます。
「静的でないフィールド、メソッド、またはプロパティ 'xxxxxx' で、オブジェクト参照が必要です。」
どうしてこのエラーが出るのでしょうか。

クラス内のメンバーはインスタンスを生成して初めて使用可能となります。
つまり、クラス内のメンバーはインスタンスごとに保持されています。
このメンバーをインスタンスメンバーと呼びます。

一方staticメソッド*1は全インスタンスに共通して保持されています。
ここで問題になるのが、staticメソッド内でインスタンスメンバーを使用する場合です。
個々のインスタンスで持っているインスタンスメンバーが、全インスタンスで共通のstaticメソッド内に配置されてしまうと、どのインスタンスメンバーを扱っているのかわからなくなります。
図で表すと以下のようになります。
f:id:shirakamisauto:20150615174744p:plain

図ではStaticMethod()から呼び出されている変数iが、myClass1、myClass2、myClass3のうち、どのインスタンスのiを指しているのかが分かりません。
これでは動作上困ってしまうので、エラーを出して禁止しているのだと思います。

もし扱いたいならば以下のようにstaticメソッド内で新しくインスタンス化してどのインスタンスを扱うか明確にする必要があります。

    public class MyClass
    {
        // インスタンスメンバー
        public int i;
        public void Function() { }
        int Prop
        {
            get
            {
                return 1;
            }
        }

        public static void StaticMethod()
        {
            var myclass = new MyClass();
            myclass.i = 10;
            myclass.Function();
            int p = myclass.Prop;
        }
    }

参考
Compiler Error CS0120

静的メンバー - C# によるプログラミング入門 | ++C++; // 未確認飛行 C

*1:というか静的メンバー