Dot-Net

將 .NET 5.0 目標添加到我的 NuGet 包

  • February 8, 2021

我發布了幾十個 NuGet 包。大多數目標是 .NET Standard。每次編譯時,Visual Studio 都可以很容易地更新這些包。

現在,我想升級這些包以充分利用 .NET 5.0。但我希望那些無法升級到 .NET 5.0 的人仍然可以使用現有的。另外,我不想創建全新的包,這樣我每個包都有兩個版本。

如果我沒記錯的話,一個 NuGet 包可以針對多個框架版本,我認為 Visual Studio 在安裝到項目中時會自動載入正確的版本。但是,創建多個包目標並沒有融入 Visual Studio。

不知道這裡有沒有NuGet包專家。我想了解這是否可行,最簡單的方法是什麼,如何處理版本控制等。有什麼好的書或文章參考嗎?

補充說明

我知道我可以在項目級別定位多個框架(使用TargetFrameworks項目文件中的元素)。但是我必須填寫我的程式碼 if #if, else,endif塊以利用每個目標框架。我不認為我想要這個。我的庫方法簽名將更改以利用可為空字元串之類的東西。我希望能夠自由地做到這一點,而無需創建所有內容的多個版本。

要走的路肯定是<TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks>在你的csproj. 然後還要啟用可空值並設置LangVersion為 v9.0。

完成此操作後,根據您現有的程式碼,您可能必鬚根據目標調整程式碼,因為 .NET 5 的所有內容都不會在裸 .Net Standard 2 中得到支持…

然而,雖然我懷疑你能否完全擺脫#if守衛,但還是有一些解決方案。

首先,我們需要區分 3 種之後出現的新奇事物netstandard2.0(即 .NET 4.6.1 和 .NET Core 2.1 時代之後)。

  • 僅依賴於編譯器的新功能:這些功能只需要最近的編譯器,但一旦編譯,舊版本的 .NET 就可以使用它們,因為它們保持完全的 IL 兼容性並且不需要執行時程序集中的新類型。例如,拋出表達式,靜態(或非)本地函式。
  • 依賴於執行時的特性:這些特性(例如Span<T>)需要最新的 CLR。如果 nuget 包必須支持 .NET Standard 2 目標,那麼這些是您想要避免的(至少在公共介面中)。
  • 中間特性 ;) 這些特性主要由編譯器支持,但在執行時提供了不那麼重要的支持。Nullables 和記錄屬於這一類:它們依賴於一些屬性(以及記錄案例中的一些新的 IL 元數據),但鑑於這些屬性是在執行時提供的,它們可以在 netstandard2.0 目標中使用。

現在,讓我們看看我們可以做些什麼來避免過多的#if. 第一個去的地方是csproj

<PropertyGroup>
 <TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks>
 <!-- enable the feature but without warning for legacy frameworks to avoid false positives. -->
 <Nullable>annotations</Nullable>
 <!-- enable the feature including warnings only on top of the most recent framework you target. -->
 <!-- it will serve as a reference for warnings for all others. -->
 <Nullable Condition="'$(TargetFramework)' == 'net5.0'">enable</Nullable>
 <LangVersion>9.0</LangVersion>
</PropertyGroup>
  • 我的目標是netstandard2.0net5.0
  • 我將語言版本設置為,9.0以便我可以使用所有最新的花里胡哨
  • 的聲明Nullable有點複雜,但基本上,它可以防止針對目標彈出警告,netstandard2.0同時完全支持.net5.0目標。

然後讓我們添加這兩個神奇的 nuget 包:

<ItemGroup>
 <PackageReference Include="IsExternalInit" Version="1.0.0">
   <PrivateAssets>all</PrivateAssets>
   <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 </PackageReference>
 <PackageReference Include="Nullable" Version="1.3.0">
   <PrivateAssets>all</PrivateAssets>
   <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
 </PackageReference>
</ItemGroup>

這兩個包是由同一個人提供的(見這里這裡)。它們是僅開發依賴項,因此不會在依賴項鍊中污染您的消費者。他們所做的只是聲明支持空值和記錄所需的屬性(作為內部類,以免與合法的衝突)。

使用此設置,您現在可以在程式碼庫中使用記錄和可為空值,並且它將成功編譯到兩個目標。

如果您使用net5.0客戶端的程序集,一切都會按預期工作。然後,如果你從一個裝配體中使用它,.NET 4.8事情也會沒問題:當然,你不會有可為空的警告或智能感知,並且記錄將被視為正常類,但我會說它很好地降級了。

#if對於最後一種特性,真正依賴於執行時的特性,如果你想使用它們,你別無選擇。假設您想將一些基於數組的程式碼替換為Span<T>… 您需要提供兩個私有實現並#if根據目標選擇正確的一個(請參閱https://docs.microsoft.com/en-us/dotnet /standard/frameworks#how-to-specify-a-target-framework獲取支持的預處理器常量列表)。

我沒有詳盡地介紹 .NET Standard 2 和 .NET 5 之間的所有變化(那可能是一本書),但這應該可以幫助您入門。我敢肯定,如果可能,聰明的人會逐個功能地找到解決方案,將它們移植到舊版本的 .NET 中。

如果你想看看,我還將我的測試遊樂場推送到這個github 儲存庫。

最後一點,我想說最重要的是進行徹底的測試,以確保現代化的程式碼庫不會破壞舊客戶的任何東西。

引用自:https://stackoverflow.com/questions/66065078