部署 ASP.NET MVC 程式遇到奇怪錯誤:

Server Error in '/' Application.
Method not found: '!!0[] System.Array.Empty()'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.MissingMethodException: Method not found: '!!0[] System.Array.Empty()'.

Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack > trace below.

Stack Trace:
[MissingMethodException: Method not found: '!!0[] System.Array.Empty()'.]
MyWeb.BundleConfig.RegisterBundles(BundleCollection bundles)
MyWeb.Global.Application_Start(Object sender, EventArgs e)

錯誤訊息居然出現 '!!0[] System.Array.Empty()' 這種鬼東西感覺超詭異,但理由卻出奇簡單 - 網站專案用 .NET 4.6 編譯,但主機的 .NET Framework 只裝到 4.5.2。

由於專案有用到 .NET 4.6 才支援的元件,所以安裝新版 .NET Framework 就對了,解法沒什麼學問,但這個 Method not found: '!!0[] System.Array.Empty()' 訊息是怎麼生出來的卻引起我的好奇。

Stackoverflow 循線查到較詳細的解釋

Roslyn Compiler 編譯程式遇到 params T[] args 參數沒傳值時,在 .NET 4.5.2 以前是使用 new T[0],.NET 4.6 後則會改使新增方法 Array.Empty<T>() 實現最佳化,例如以下範例,Test(params string[] args) 的 args 參數允許 0 到多個,不傳任何參數呼叫 Test() 時,查看編譯出來的 IL,args 會放入 System.Array.Empty<String>:

因此,當這段程式在 .NET 4.6 以下平台跑,便會因沒有 Array.Empty() 方法出錯。但,!!0[] 又是什麼鬼?

兩個驚嘆號加零,這關鍵字超難 Google 的,我最後是在 ECMA-335 Common Language Infrastructure (CLI) 標準找到答案 (II.9 Generics p.128) (讀了一陣子 C# in Depth,意外收獲是現在的我有勇氣翻開 CLI 規範文件不會想吐 😄)

Within a generic type definition, its generic parameters are referred to by their index. Generic parameter zero is referred to as !0, generic parameter one as !1, and so on.
Similarly, within the body of a generic method definition, its generic parameters are referred to by their index; generic parameter zero is referred to as !!0, generic parameter one as !!1, and so on.

泛型型別定義中的泛型參數可寫成 !0、!1;而在泛型方法定義中,泛型參數會寫成 !!0、!!1。

實測了一下,若為已知型別,Reflection 均正確識別出 T、K、D 之類的泛型參數名詞。!!0、!!1 應是編譯後 IL 對應不到 .NET Framework 型別才會出現的特殊結果。

就醬,又解開一些謎團,開心。

【補充】感謝讀者 Pei-Cheng Huang 提醒,.NET Framework 4.5.2、4.6 和 4.6.1 的支援將於 2022 年 4 月 26 日終止。程式不需重 Build,但執行環境要安裝新版,參考:

Method not found: '!!0[] System.Array.Empty()' is the typical error message when running program compiled by .NET 4.6 on .NET 4.5.2 platform, I try to find out how it happened and what does the !!0[] mean.


Comments

Be the first to post a comment

Post a comment