1. 程式人生 > >Zfrong繁榮的IT技術、IT專案、解決方案專欄Blog-上海

Zfrong繁榮的IT技術、IT專案、解決方案專欄Blog-上海

 C#泛型類的靜態建構函式及靜態成員[經典]

靜態建構函式總是至多被呼叫一次嗎?靜態建構函式一定會被呼叫嗎?看如下反例:

namespace ConsoleApplication1
{
    class Program:A<float>
    {
        static Program()
        {
            Console.WriteLine("Class Program static construct invoked.");
        }

        static void Main(string[] args)
        {
            Console.WriteLine(B.SomeValue++);
            Console.WriteLine(C.SomeValue++);
            Console.WriteLine(D.SomeValue++);
            Console.WriteLine(E.SomeValue++);
            Console.WriteLine(E.SomeValue2++);

            new F();
            new F();

            Console.ReadKey();

        }
    }

    class A<T>
    {
        public static int SomeValue=0;

        public A()
        {
            Console.WriteLine("Class A<{0}> dynamic construct invoked.", typeof(T).Name);
        }


        static A()
        {
            Console.WriteLine("Class A<{0}> static construct invoked.",typeof(T).Name);
        }
    }

    class B : A<string>
    {
        static B()
        {
            Console.WriteLine("Class B static construct invoked.");
        }
    }


    class C : A<int>
    {
        static C()
        {
            Console.WriteLine("Class C static construct invoked.");
        }
    }

    class D : A<int>
    {
        static D()
        {
            Console.WriteLine("Class D static construct invoked.");
        }
    }

    class E : A<float>
    {
        public static int SomeValue2 = 0;
        static E()
        {
            Console.WriteLine("Class E static construct invoked.");
        }
    }

    class F : A<bool>
    {
        public F()
        {
            Console.WriteLine("Class F dynamic construct invoked.");
        }

        static F()
        {
            Console.WriteLine("Class F static construct invoked.");
        }
    }

}


輸出 如下:
Class Programe static construct invoked.
Class A<String> static construct invoked.
0
Class A<Int32> static construct invoked.
0
1
Class A<Single> static construct invoked.
0
Class E static construct invoked.
0
Class F static construct invoked.
Class A<Boolean> static construct invoked.
Class A<Boolean> dynamic construct invoked.
Class F dynamic construct invoked.
Class A<Boolean> dynamic construct invoked.
Class F dynamic construct invoked.

對輸出結果分析如下:

//程式執行實際上是Framework呼叫Program 的Main靜態方法,但不會例項化Program
Class Program static construct invoked.  
// 實際上靜態成員並不支援繼承,C#編譯器會在底層將B.SomeValue翻譯成A<string>.SomeValue
//所以被 載入的不是B,而是A<string>
Class A<String> static construct invoked. 
0
//同樣此處C.SomeValue被翻譯成A<int>.SomeValue
Class A<Int32> static construct invoked.
//詫異?被繼承的SomeValue不是被“加加”了嗎, 為何此處還是0
0
//看到了吧,SomeValue確實被“加加”了,不過A<string>與A<int>屬 於不同的型別
//裡面的SomeValue也是相互獨立的
1
//E.SomeValue被翻譯成 A<float>.SomeValue
Class A<Single> static construct invoked.
0
//此處的E.SomeValue2遠遠本本的就是E.SomeValue2當然E的靜態建構函式會被執行。
// 現在我們才發覺B/C/D三者的靜態建構函式都沒被執行,原因呢,剛才也說了,實際上
//上面的B/C/D的引用在底層都被翻譯成了A的封閉類, 所以載入的並不是B/C/D本身,而是
//相應的封閉類
Class E static construct invoked.
0
// 現在再來溫習一下靜態構造方法與構造方法的執行順序
//因為new的是F,所以F首先被載入,進而執行F的靜態構造
Class F static construct invoked.
//載入F後發現F是從A<bool>繼承的,進而去載入 A<bool>,於是A<bool>的靜態構造被執行
Class A<Boolean> static construct invoked.
//首先執行基類的構造方法
Class A<Boolean> dynamic construct invoked.
//而後是F自己的構造方法
Class F dynamic construct invoked.
//此兩句因為A<bool>與F以被載入,靜態構造已被執行,因而直接按順序從低往高呼叫構造方法
Class A<Boolean> dynamic construct invoked.
Class F dynamic construct invoked.

QQ 1163551688
總結:
1.泛型類的各封閉類,屬於不同的類,各自有自己獨立的靜態空間
2. 靜態成員實際上不支援繼承,C#編譯器在底層將實際的引用確定成靜態成員定義者
3.靜態建構函式不一定會被執行,因為有的類,在執行過程中不會被 載入
4.靜態建構函式確實是總是至多被呼叫一次,但是泛型類的靜態構造要站在另一個角度考慮
5.類的建構函式執行順序是自底而上
6. 類的靜態建構函式執行順序是不能確定的,因為程式設計過程中,類的使用順序是不定的,靜態建構函式總是在類第一次被用到的地方執行