2016-03-11 45 views

回答

3

CLR維護一個已加載的所有類型的表格及其初始化狀態。如果A正在使用B的靜態字段,則CLR知道A正在使用B,並且在初始化A時它還將初始化B。因此,檢查依賴關係是否被初始化並不是在每個訪問上執行的。它通過類型的依賴關係圖來保證。

如果您感興趣的實現細節,你可以看看DomainLocalModuleIsClassInitialized方法CoreCLR及其usage創建類的實例時。

我希望這能回答你的問題。

+0

是的,非常感謝。雖然我不得不承認,但在訪問某個字段時(例如,與C++比較),每次檢查代價都很昂貴。 –

+0

要清除此類檢查,不會在每次訪問該類時執行此檢查。加載使用類時會檢查類加載狀態。如果您的類A使用B.foo的靜態屬性,那麼當使用A時,將檢查它的依賴關係。所以當A初始化時,B也會被初始化。對B.foo的訪問不會產生這樣的檢查。 – Kolja

+0

我已經對答案做了一些編輯,以便在此檢查發生時更加清楚。 – Kolja

2

static class第一次初始化其中一個字段被引用,這很容易。

不,不是那麼簡單。忽略方法調用,static類必須在它的第一個字段被初始化之前初始化,如果它沒有標記爲beforefieldinit。如果標記爲beforefieldinit,則可以在此之前進行初始化。 (Jon Skeet有an article with lots more information about beforefieldinit。)

這是如何影響何時檢查類初始化的?由於CLR使用JIT編譯,所以它會在JIT編譯方法時檢查類的初始化。如果該類標記爲beforefieldinit且尚未初始化,則JIT編譯器會立即對其進行初始化。然後它實際上編譯該方法,它可以假定該類已經被初始化,所以不需要檢查。

沒有beforefieldinit,如果類尚未初始化,JIT編譯器必須發出代碼,以便在每次可能的第一次字段訪問之前檢查初始化。但是如果這個類已經被初始化了,並且另一個方法正在被JIT編譯,JIT編譯器就不必再在那裏發出檢查了。

在某些情況下,這會對性能產生負面影響。從上面很清楚,爲了防止這種情況發生,您需要確保有問題的類別標記爲beforefieldinit。而從C#做到這一點的方式是沒有static構造函數,只使用static字段初始值設定項。

+0

有趣。如果潛在的第一個字段Access在整個解決方案中大量依賴並且嚴重依賴於外部輸入,我想這會特別成問題。非常感謝您的深入解答。 –