1 背景動機
關于模塊或者程式集初始化作業一直是C#的一個痛點,微軟內部外部都有大量的報告反應很多客戶一直被這個問題困擾,這還不算沒有統計上的客戶,那么解決這個問題,還有基于什么樣的考慮呢?
-
在庫加載的時候,能以最小的開銷、無需用戶顯式呼叫任何介面,使客戶做一些期望的和一次性的初始化,
-
當前靜態建構式方法的一個最大的問題是運行時會對帶有靜態建構式的型別做一些額外的檢查,這是因為要決定靜態建構式是否需要被運行所必須的一步,但是這個又有著顯著的開銷影響,
-
使源代碼生成器在不需要用戶顯式呼叫一些東西的情況下能運行一些全域的初始化邏輯,
2 詳細設計
C# 9.0將模塊初始化器設計為一個Attribute,用這個Attribute來修飾進行模塊初始化邏輯的方法,就實作了模塊初始化功能,這個Attribute被命名為ModuleInitializerAttribute,具體定義如下:
using System;
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public sealed class ModuleInitializerAttribute : Attribute { }
}
如果要使用模塊初始化器,你只要將ModuleInitializerAttribute用在符合下面要求的方法上就可以了,
-
該方法必須使靜態的、無參的、回傳值為void的函式,
-
該方法不能是泛型或者包含在泛型型別里
-
該方法必須是可從其所在模塊里訪問的,也就是說,方法的有效訪問符必須是internal或者public,不能是區域方法,
using System.Runtime.CompilerServices;
class MyClass
{
[ModuleInitializer]
internal static void Initializer()
{
// ...
}
}
被修飾為ModuleInitializerAttribute的靜態方法會被編譯器在編譯時,在全域的靜態建構式中生成此代碼呼叫,如果有多個被修飾為初始化器的函式,則每個函式生成一個初始化器代碼呼叫,這些初始化器代碼呼叫代碼會按照一定的順序(型別名稱順序和代碼順序)生成,當模塊在被加載時,全域靜態建構式開始執行,從而完成模塊代碼初始化作業,
3 問題與最佳實踐
模塊初始化器與靜態建構式之間有著一定的關聯影響,因為模塊初始化器是一個靜態方法,因而其被呼叫執行前,必然會引起其所處型別的靜態建構式的執行,請參考下列示例:
static class ModuleInit
{
static ModuleInit()
{
//先執行
Console.WriteLine("ModuleInit靜態建構式 cctor");
}
[ModuleInitializer]
internal static void Initializer()
{
//在靜態建構式執行后才執行
Console.WriteLine("模塊初始化器");
}
}
在一個模塊中指定多個模塊初始化器的時候,他們之間的順序也是一個值得注意的問題,以上這些問題的存在,就要求我們注意以下幾點:
-
在指定了模塊初始化器的型別中,不要在靜態建構式中,寫與模塊初始化器中代碼有著順序依賴代碼,最好的就是不要使用靜態建構式,
-
多個模塊初始化器之間的代碼,也不要有任何依賴關系,保持各個初始化器代碼的獨立性,
4 結束語
日常開發中,我們通常需要在模塊初始化的時候,做一些前置性的準備作業,以前常采用靜態建構式這種不具有全域性方法,局限性很大,現在,這些都得到了完美解決,
如對您有價值,請推薦,您的鼓勵是我繼續的動力,在此萬分感謝,關注本人公眾號“碼客風云”,享第一時間閱讀最新文章,
<iframe style="background: rgba(255, 255, 255, 1)" src="https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1612459507345899521&__biz=MzAwNjcyNTU2Ng==#wechat_redirect" frameborder="0" width="100%" height="342"></iframe>
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/228218.html
標籤:C#
上一篇:關于C# Span的一些實踐
