在 Visual Studio 2019 新增 Class Library (類別程式庫)專案,現在有三個選項:

  • Class Library (.NET Standard)
  • Class Library (.NET Framework)
  • Class Library (.NET Core)

這篇簡單聊聊如何抉擇與實現類別程式庫跨平台。

開始前請確定你知道 .NET Standard 是什麼?簡單說它是針對 .NET 跨平台共用所制定的一套標準,確保依此標準寫出來的程式庫可以在 .NET Framework、.NET Core、Mono、UWP、Xamarin.iOS、Xamarin.Android (原本還有 Windows Phone,現在已經沒有了,鳴...) 等不同平台使用。

抓住這一點,如何選擇就很清楚了。如果你的開發環境只有 .NET Framework 及 .NET Core 兩種,程式庫想要兩邊共用,那 Class Library (.NET Standard) 是唯一選擇,否則,要給誰專用就選哪一種。

為什麼不一律都用 .NET Standard 就好?

.NET Standard 考量跨平台相容,限定只能使用各平台都能支援的 API,.NET Standard 版本從 1.0、1.1 到目前的 2.1 版,愈早的版本能支援的平台版本愈廣,相對的可用 API 也愈少。


表格來源: https://docs.microsoft.com/zh-tw/dotnet/standard/net-standard

若主要考量 .NET Core、.NET Framework 兩種平台,只能選 .NET Standard 2.0(含) 以下的版本,.NET Standard 2.1 可對映 .NET Core 3.0+,但 .NET Framework 無法支援,最高只能到 .NET Standard 2.0。(延伸閱讀:.NET Core 3.0 正式版! 告別 .NET Framework ,迎向 .NET 5)

.NET Standard 程式庫需依循某個特定數字版本,若考慮通吃 .NET Core 加 .NET Framework,.NET Standard 2.0 算是唯一解:

選 2.1 .NET Framework 不能用,選 2.0 以下的理論上也成,但愈低的版本能用的 API 愈少。別小看 API 數量差距,1.6 可用的 API 還不到 2.0 的一半 (13,501 vs 32,638),想拿慣用老虎鉗卻發現工具箱沒有,可以想像那感覺有多糟 XD:


來源:.NET Standard FAQ

如果你的程式邏輯單純,沒有綁不同平台專屬的動作,TargetFramework 選 .NET Standard 2.0,編譯成一顆 DLL 給所有平台用是最省事的方法。但老鳥都知道,代誌母系憨人所想 A 哈尼甘單,難免遇到不同平台做法有別的情境,例如:在 .NET Framework 讀 Registry,在 .NET Core 吃環境變數。此時需針對不同平台執行不同邏輯,.NET Standard 程式庫提供的做法是修改 .csproj,將 <TargetFramework>netstandard2.0</TargetFramework> 更名為 <TargetFrameworks> (加上s),並以分號分隔列舉 Target Framework Moniker (TFM),而引用程式庫時,可加上 Condition 指定不同 TargetFramework 參照不同程式庫。加入多個 TargetFramework 後 /bin/Debug 資料也會出現以 TFM 為名的資料夾:

以 TFM 為名的資料夾,內含該平台專用的 DLL 及相依組件庫:

程式部分則用 #if NET461、#if NETFRAMEWORK、#if NETSTANDARD2_0、#if NETSTANDARD、#else、#endif 等語法為不同平台撰寫專屬邏輯:參考 (註:程式是亂寫的,請不要問為什麼有這種鬼邏輯。)

using System;

namespace NetStdClassLib
{
    public class Foo
    {
        public static string Test()
        {
#if NET461
            return Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\.NETFramework")
                .GetValue("InstallRoot").ToString();
#else
            return Environment.GetEnvironmentVariable("TEMP");
#endif
        }
    }
}

使用多 TargetFramework 雖然不像標準 .NET Standard 程式庫用同一個 DLL 通吃各平台,但至少能做到單一專案維護多平台共用程式庫,但畢竟是次佳解,在系統開發時仍應優先考量使用 .NET Standard。

Tips of developing .NET Standard class library with Visual Studio.


Comments

# by cyy

這個有個問題在寫代碼的時候會按第一個來判斷語法是否合法,寫一些.net 4.7才有的語法糖就會提示不支持

# by 余小章

當我用 Net Standard 編譯多平台,專案設定如下 <PropertyGroup> <TargetFrameworks>net40;net45</TargetFrameworks> </PropertyGroup> 代碼裡面會有 #if NET40 ... #if NET45 ... #if NET 45 區段的代碼是淺色的,編譯時沒有 Intellisense,除錯時,不會執行; 當專案設定 <TargetFrameworks>net45;net40</TargetFrameworks> 順序交換,然後重開 VS,換 #if NET40 的代碼變淺色 XD

# by 余小章

或者,在 VS IDE 的編輯視窗左上角選擇 TargetFramework,這樣就不需要重新啟動 VS IDE

Post a comment