在 “One .NET” 這個目標下,.NET 框架可以用來開發各種平台的程式,而除了執行環境的平台外,.NET 自己本身也有各種因時代演進而誕生的各種框架平台,在開發 .NET 的 NuGet 套件時,特別容易會遇到為了讓套件適用於各個 .NET 框架平台的情境,因此有些跨平台的開發技巧必須知道,才能在面對各個框架所支援的 API 差異。
.NET 文件中所稱的”平台”有 2 種可能,一種是執行環境的平台,如 Windows、MacOS、Linux,另一種平台是 .NET 框架的平台,如 .NET Framework、.NET Core、.NET Standard 等,避免混亂,建議後者用目標框架來稱呼。
設定成可以建置多目標框架
打開 .csproj 專案檔,可以看到預設所使用的 TargetFramework 屬性,這指定了此專案要在哪個目標框架下執行。
1 | <Project Sdk="Microsoft.NET.Sdk"> |
如果要建置可以支援多個目標框架,只要把 TargetFramework(單數)改成 TargetFrameworks(複數),並在其中的設定中加上你要支援的目標框架名稱,並用 ; 分隔就可以了。
以下設定就可以支援 .NET Framework 4.8 和 .NET 6 這兩個目標框架:
1 | <Project Sdk="Microsoft.NET.Sdk"> |
支援的目標框架名稱
官方用 Target Framework Moniker (TFM) 來表示目標框架名稱,你可以參考下列簡表,或從這份官方文件中找到詳細列表:
| Name | TFM |
|---|---|
| .NET Framework | net46 |
| net462 | |
| net47 | |
| net472 | |
| net48 | |
| .NET Standard | netstandard1.6 |
| netstandard2.0 | |
| netstandard2.1 | |
| .NET 5+ (and .NET Core) | netcoreapp3.1 |
| net5.0 | |
| net6.0 |
如果你想要針對某一個特定執行環境,也就是特定作業系統的目標框架做設定,可以使用像是 net 6.0-windows、net 6.0-macos、net 6.0-android 這樣的設定方式,但其相容性要再檢查一下,或透過平台相容性分析器幫助你檢查。
針對專案檔的設定做調整
專案檔內的設定也有可能會依目標框架的不同而有不同的設定,例如在 .NET Framework 需要某些套件,而 .NET Core 的需要另一種。
這時候可以使用 MSBuild 所提供的條件式建構來處理。
最基本的用法就是使用 Condition 並針對當前要編譯的 TargetFramework 做條件判斷,程式碼範例如下:
1 | <Project Sdk="Microsoft.NET.Sdk"> |
這最常見於不同目標平台需要使用不同的套件或版本。
前置處理器指示詞
如果你想要直接針對程式碼做處理呢?
對於某些 API 可能存在新版、舊版有不同的支援,例如在 .NET Framework 會用到 WebClient 這個類別,而較新的目標框架,則會建議使用 HttpClient 來處理。
這時候可以使用 C# 的前置處理器指示詞來修正程式碼,這會讓編譯器在編譯特定平台時,套用並編譯所指定的程式碼,藉此達到條件式編譯的效果。
1 |
|
至於什麼目標平台要用什麼指示詞,你可以參考下列簡表,或從這份官方文件中找到詳細列表:
| Target Frameworks | Symbols | Additional symbols available in .NET 5+ SDK |
|---|---|---|
| .NET Framework | NETFRAMEWORK, NET48, NET472, NET471, NET47, NET462, NET461, NET46 |
NET48_OR_GREATER, NET472_OR_GREATER, NET471_OR_GREATER, NET47_OR_GREATER, NET462_OR_GREATER, NET461_OR_GREATER, NET46_OR_GREATER |
| .NET Standard | NETSTANDARD, NETSTANDARD2_1, NETSTANDARD2_0, NETSTANDARD1_6 |
NETSTANDARD2_1_OR_GREATER, NETSTANDARD2_0_OR_GREATER, NETSTANDARD1_6_OR_GREATER |
| .NET 5+ (and .NET Core) | NET, NET6_0, NET6_0_ANDROID, NET6_0_IOS, NET6_0_MACOS, NET6_0_MACCATALYST, NET6_0_TVOS, NET6_0_WINDOWS, NET5_0, NETCOREAPP, NETCOREAPP3_1 |
NET6_0_OR_GREATER, NET6_0_ANDROID_OR_GREATER, NET6_0_IOS_OR_GREATER, NET6_0_MACOS_OR_GREATER, NET6_0_MACCATALYST_OR_GREATER, NET6_0_TVOS_OR_GREATER, NET6_0_WINDOWS_OR_GREATER, NET5_0_OR_GREATER, NETCOREAPP_OR_GREATER, NETCOREAPP3_1_OR_GREATER |
後記
有了這些技巧,可以讓我們更好的處理多目標框架的專案。
不過用多了你會發現,程式碼變得相當雜亂,一點都不清爽,所以釐清所要相容的目標框架,並適度的使用,才是上策。
參考資料: