1. 程式人生 > >提高C#程式設計水平的50個要點 之十三“使用靜態建構函式來初始化靜態成員變數”

提高C#程式設計水平的50個要點 之十三“使用靜態建構函式來初始化靜態成員變數”

  編寫程式的時候難免要使用到靜態成員,由於靜態成員的訪問是脫離型別物件的,所以使用非靜態建構函式,私有方法或者一些其他方法進行靜態變數的初始化都是不合理的。

  .net提供了成員初始化語句和靜態建構函式來初始化靜態成員,但我們知道靜態成員的初始化語句會早於靜態建構函式執行,其次還知道成員初始化語句的好處和一些限制。要提的一點就是,靜態建構函式和例項建構函式之間的區別,因為靜態建構函式是由CLR呼叫執行的,所以靜態建構函式只能是一個,同時不能還有引數。那麼靜態建構函式相對於成員初始化的一些弊端都不復存在。 
此外,對於成員初始化最大的問題,就是異常無法捕獲,可能對於普通成員來說,還可以在構造型別物件的時候加上try-catch;而對於靜態成員來說,有時無法確定哪一個型別訪問語句會先執行,如果對每個使用型別的地方都加上try-catch,會降低程式可讀性。但如果把這種異常散發出去,會導致整個程式崩潰。那麼使用靜態建構函式就能比較好的捕獲異常,並進行異常處理。

初始化靜態成員有以下兩點建議: 

1、簡單靜態成員,例如型別為值型別等,使用成員初始化語句來完成; 
2、靜態成員初始化比較複雜,或者有可能出現異常,那麼用靜態建構函式來完成。

初始化靜態成員變數程式碼分析案例:

class A 
  { 
   public static int X = B.Y; 
   static A() 
   { 
    ++X; 
   } 
  } 

  class B 
  { 
   public static int Y = A.X; 
   static B() 
   { 
    ++Y; 
   } 
  } 
那麼如下呼叫輸出結果是什麼。 
  Debug.WriteLine( A.X.ToString() ); 


  Debug.WriteLine( B.Y.ToString() ); 
    其結果是“2,1”,也就是A.X的值為2,而B.Y的值為1。 
    分析此類問題,只要記住三點就行了。 
    1、程式碼的執行順序,程式碼在前的先執行; 
    2、靜態成員初始化語句要先於靜態建構函式執行; 
    3、靜態成員初始化語句與靜態建構函式只執行一次。 


  如果瞭解這三點,接下來就分析為什麼會出現上面的結果。 當呼叫到第一條語句的時候, 
 Debug.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,這也就是最後顯示的結果。