2008-09-23 240 views
6

好吧,所以我碰到以下問題,提出了眉毛。Assembly.GetCallingAssembly()和靜態構造函數?

由於各種原因,我有一個測試設置,其中TestingAssembly.dll中的測試類取決於BaseTestingAssembly.dll中的TestingBase類。 之一TestBase確實在此期間的一件事就是尋找在自己的一定的嵌入式資源和調用程序集

所以我BaseTestingAssembly包含以下幾行...

public class TestBase {  
    private static Assembly _assembly; 
    private static Assembly _calling_assembly; 

    static TestBase() { 
    _assembly = Assembly.GetExecutingAssembly(); 
    _calling_assembly = Assembly.GetCallingAssembly(); 
    } 
} 

靜態,因爲我想通,這些程序集在應用程序的整個生命週期中都是一樣的,所以爲什麼還要在每次測試時重新計算它們。

運行這個時,我注意到_assembly和_calling_assembly分別被設置爲BaseTestingAssembly而不是BaseTestingAssembly和TestingAssembly。

將變量設置爲非靜態,並讓它們在常規構造函數中初始化,但我很困惑爲什麼發生這種情況。我認爲靜態構造函數第一次運行靜態成員被引用。這隻能來自我的TestingAssembly,它應該是調用者。有誰知道可能發生了什麼?

回答

5

靜態構造函數是在執行上沒有控制由運行時調用,而不是由用戶代碼直接調用。您可以通過在構造函數中設置斷點並在調試器中運行來看到這一點。緊挨着它的調用鏈中的函數是本地代碼。

編輯:靜態初始化器在其他用戶代碼中運行的環境有很多種。其他一些方法是

  1. 他們免受多線程
  2. 不能從初始化

一般外面捕捉異常導致競爭條件暗中保護,它可能是最好不要使用它們因爲任何事情都太複雜您可以使用以下模式實現單啓動:

private static Assembly _assembly; 
private static Assembly Assembly { 
    get { 
    if (_assembly == null) _assembly = Assembly.GetExecutingAssembly(); 
    return _assembly; 
    } 
} 

private static Assembly _calling_assembly; 
private static Assembly CallingAssembly { 
    get { 
    if (_calling_assembly == null) _calling_assembly = Assembly.GetCallingAssembly(); 
    return _calling_assembly; 
    } 
} 

如果您期望多線程訪問,請添加鎖定。

+0

那麼爲什麼調用程序集不是null呢? – 2008-09-23 16:23:11

1

我認爲答案在這裏討論C# static constructors。我最好的猜測是,靜態構造函數正從一個意想不到的情況下調用,因爲:

用戶具有當 靜態構造函數在 程序

+0

其實你有一些控制:) – leppie 2008-12-04 16:12:54

1

Assembly.GetCallingAssembly()只是返回調用堆棧中第二個條目的程序集。這可以非常依賴於你的方法/ getter /構造函數的調用方式。這是我在圖書館做的,以獲得不在我的圖書館的第一個方法的彙編。 (這甚至可以在靜態構造函數中使用。)

private static Assembly GetMyCallingAssembly() 
{ 
    Assembly me = Assembly.GetExecutingAssembly(); 

    StackTrace st = new StackTrace(false); 
    foreach (StackFrame frame in st.GetFrames()) 
    { 
    MethodBase m = frame.GetMethod(); 
    if (m != null && m.DeclaringType != null && m.DeclaringType.Assembly != me) 
     return m.DeclaringType.Assembly; 
    } 

    return null; 
}