Staticクラスに対する認識

32064 ワード

Design&PatternのSingleton Patternを勉強するとき、静的初期化は.NETの中でSingletonを実現する第一選択方法.

  
1 public sealed class Singleton
2 {
3 static readonly Singleton instance = new Singleton();
4
5 static Singleton()
6 {
7 }
8
9 Singleton()
10 {
11 }
12
13 public static Singleton Instance
14 {
15 get
16 {
17 return instance;
18 }
19 }
20 }

しかし、私は静的構造関数に少し迷っています.オブジェクトをインスタンス化するときのコンストラクション関数とどのような違いがありますか.それらの関係は何ですか.関連資料を調べた後、今それに対して一定の認識がありました!静的メンバーの初期化文は静的コンストラクション関数よりも早く実行され、次に静的コンストラクション関数はCLR呼び出しによって実行されるため、静的コンストラクション関数は1つのみであり、パラメータも持つことはできません.静的構造関数は、メンバーの初期化に対するいくつかの弊害は存在しない.静的メンバーがいつ初期化され、静的構造関数がいつ呼び出されるかについて、それらの間の優先順位はどのようになりますか?次に例を挙げて説明します!

  
1 using System;
2
3   namespace testStatic
4 {
5 class Program
6 {
7 static void Main( string [] args)
8 {
9 Console.WriteLine(A.X.ToString()); // Return: 2
10   Console.WriteLine(B.Y.ToString()); // Return: 1
11  
12 Console.Read();
13 }
14 }
15
16 class A
17 {
18 public static int X = B.Y;
19
20 static A()
21 {
22 ++ X;
23 }
24 }
25 class B
26 {
27 public static int Y = A.X;
28
29 static B()
30 {
31 ++ Y;
32 }
33 }
34 }

正直、私は以前のstaticに対する認識の基礎の上で私は本当に上のがどんな値を返すことができることを知りません!(人间として诚実で、知らないで知っているふりをしてはいけません!ほほほ....)その結果、A.Xの値が2、B.Yの値が1となる.このような問題を分析するには、3点を覚えればいい:1.コードの実行順序、コードは前の先に実行します;2.静的メンバー初期化文は静的構造関数より先に実行する.3.静的メンバー初期化文と静的構造関数は一度だけ実行されます.
この3つの点を理解したら、次に、なぜ上記の結果が出たのかを分析します.最初の文が呼び出されたとき:Console.WriteLine(A.X.ToString());まずAというタイプにアクセスするには、Aというタイプの静的メンバーを初期化し、次に静的構造関数がある場合は呼び出す必要があります.Aの静的メンバーについては「X」のみであり、前のユニットの手順に従って空間を割り当て、0を補助して初期化し、次に対応するメンバー初期化文を呼び出して静的メンバーを初期化する.メンバー初期化文が「X=B.Y」である場合、「B.Y」にアクセスしてXという静的メンバーを初期化する必要があります.「B.Y」へのアクセスは、アクセスBタイプであり、アクセスAと同様に、まずこのタイプの静的メンバーを初期化し、次に静的構造関数があれば呼び出す必要がある.一方、Bの静的メンバーは「Y」のみであり、まず空間を割り当て、0を補助して初期化し、次に対応するメンバー初期化文を呼び出して静的メンバーを初期化する.では、「Y=A.X」メンバー初期化文では、この時点では最初のアクセスタイプAではないため、静的メンバー初期化および静的構造関数の呼び出しは行われず、「A.X」へのアクセスは直接アクセスである.このとき「A.X」の値が0であれば、Yの値も0である.次に、Bの静的構造関数を実行し、処理後Yの値を1とする.では、Aのメンバー初期化文「X=B.Y」については、これで実行が完了します.この場合、AタイプのXとBタイプのYは同じで、値は1です.ただし、Bの静的メンバー初期化文と静的コンストラクション関数はすべて実行されたが、Aの静的コンストラクション関数はまだ実行されていない.したがって,Aの静的構造関数処理により,AのX値は2となり,これが最後に示す結果となる.
もう少しStaticに対する印象を深めるために、もう一つの小さなテスト断片!これでStaticに対する印象が深まりました~`

  
1 using System;
2   using System.Collections.Generic;
3 using System.Text;
4 using System.Threading;
5
6 namespace testStatic
7 {
8 class Program
9 {
10 static void Main( string [] args)
11 {
12 // Console.WriteLine(A.X.ToString());
13 // Console.WriteLine(B.Y.ToString());
14 A objA = A.Instance;
15
16 Console.WriteLine(objA.GetStr());
17
18 Console.Read();
19 }
20 }
21
22 class A
23 {
24 static A instance = null ;
25
26 string str = " i am A, i am a member of class A " ;
27
28 public static int X = B.Y;
29
30 /// <summary>
31 /// .
32 /// </summary>
33 static A()
34 {
35 ++ X;
36 Console.WriteLine( " hello A. I am from static A constructor " );
37 }
38 private A()
39 {
40 Console.WriteLine( " hello A. I am from private A constructor " );
41 }
42
43 public string GetStr()
44 {
45 return str;
46 }
47
48 public static A Instance
49 {
50 get
51 {
52 //
53 return instance = new A();
54 }
55 }
56
57
58 }
59 class B
60 {
61 //
62 public static int Y = A.X;
63 /// <summary>
64 ///
65 /// </summary>
66 static B()
67 {
68 ++ Y;
69 Console.WriteLine( " hello B . I am from static B constructor " );
70 }
71
72
73 /// <summary>
74 ///
75 /// </summary>
76 private B()
77 {
78 Console.WriteLine( " hello B . I am from private B constructor " );
79 }
80 }
81 }

出力:hello B.I am from static B constructorhello A. I am from static A constructorhello A. I am from private A constructori am A, i am a member of class A
まず例を見てみましょう.

  
1 using System;
2
3 Class A
4 {
5 static int X;
6 static A()
7 {
8 X = B.Y + 1
9 }
10 }
11
12 Class B
13 {
14 public static int Y = A.X + 1 ;
15 static B() {}
16
17 static void Main()
18 {
19 Console.WriteLine( " X={0},Y={1} " ,A.X,B.Y);
20 }
21
22 }

実行結果はX=2,Y=1
この例は主に2つの側面を調べ,1つはstaticの用法,2つはstaticの初期化順序である.staticの初期化順序とルールを理解すると,この問題の答えは容易に理解できる.ここでは、staticメンバー、staticメソッド、static構造関数の3つのstaticオブジェクトについて説明します.ルールは次のとおりです.
1つのクラスのstaticコンストラクション関数は、指定されたアプリケーションドメインで1回のみ実行されます.staticコンストラクション関数は、アプリケーションドメインの次のイベントの最初の発生時にトリガーされます.1)クラスのインスタンスが作成されます.2)いずれかのstaticメンバが参照される3)クラスに実行エントリMainメソッドが含まれている場合,そのようなstaticコンストラクタはMainメソッドが呼び出される前に実行される.4)クラスにstaicメンバーが含まれている場合、これらのstaticメンバーはstaticコンストラクション関数の前に初期化されます.5)クラスにstaticメソッドが含まれている場合、これらのstaticメソッドはstaticコンストラクション関数の後に初期化されます.6)複数のstaticメンバーが存在する場合、呼び出し順序によって初期化はテキスト順に行われます.
上のアプリケーションを見てみると、Class BにはMain実行エントリがあるので、BはまずstaticメンバーY->staticコンストラクション関数の順に初期化されます.Yを初期化するときにA.Xを参照すると、コンパイラはまたClass Aの初期化を開始し(このときClass Bの初期化は完了していないことに注意)、順序もstaticメンバーX->staticコンストラクタです.Class AでXは定義時に初期値が付与されず(static変数を定義する場合はなるべく初期値が付与される)、コンパイラはデフォルトで値0(int型)が付与される.その後staticのコンストラクション関数を実行するが、Class Bの初期化はまだ完了していないため、B.Yの値はこのときコンパイラにデフォルト値0が与えられるので、Aのstaticのコンストラクション関数の実行が完了すると、Xの値は1となり、Bに戻って初期化を完了し続け、Yの値は2となる.最後にMainを実行し、A.XとB.Yの値を出力します.逆に,BのMainメソッドをクラスCに移動すると,実行結果は何であるか.以上のルールに基づいて、答えを簡単に出すことができます.
以下の問題はルール6を説明するのに使えます.興味のある人は答えを考えてみてください.

  
class Class1
{
private static Class1 obj = new Class1();
public static int counter1;
public static int counter2 = 0 ;
private Class1()
{
counter1
++ ;
counter2
++ ;
}
public static Class1 getInstance()
{
return obj;
}

[STAThread]
static void Main( string [] args)
{
Class1 obj
= Class1.getInstance();
Console.WriteLine(
" Class1.counter1== " + Class1.counter1);
Console.WriteLine(
" Class1.counter2== " + Class1.counter2);

}
}