1. 程式人生 > >讓一個 csproj 項目指定多個開發框架[轉]

讓一個 csproj 項目指定多個開發框架[轉]

-- intro studio 條件編譯 種類型 直接 href configure 裏的

原貼:https://walterlv.gitee.io/post/configure-projects-to-target-multiple-platforms.html

可移植類庫、共享項目、.NET Standard 項目都能夠幫我們完成跨多個 .NET SDK 的單一項目開發,但它們的跨 SDK 開發都有些限制。現在,我們又有新的方式能夠跨多個 .NET SDK 開發了,這就是使用新的 csproj 文件格式。


看看擁有多個開發框架的項目長什麽樣吧!

技術分享圖片

這個是我和 erdao 在 GitHub 上開源項目 dotnet-campus/MSTestEnhancer 的項目依賴截圖。是不是很激動?

本文內容
  • 新 csproj 文件
  • 如何指定多個開發框架
  • 多框架項目的坑以及如何避坑
    • 參考資料

新 csproj 文件

在 如何組織一個同時面向 UWP/WPF/.Net Core 控制臺的 C# 項目解決方案 - walterlv 一文中我講了 .NET Standard 的方式,這種方式優勢非常明顯,跟普通的開發方式一樣,也是我最推薦的方式。但缺點是要求目標 SDK 支持對應的 .NET Standard 版本。

使用共享項目的方式則是直接共享了源碼,只要在目標項目中指定了條件編譯符,那麽源碼便能針對各種不同的目標框架進行分別編譯。但缺點是對擴展插件的支持較差(可能是因為擴展插件難以判斷項目的真實開發框架),而且 Visual Studio 本身對它的支持也有 BUG(例如切換編寫文件所屬的項目經常會失敗)。

新的 csproj 文件能夠指定多個開發框架。這樣,我們便能同時編寫適用於 .NET Framework 4.5 的和 .NET Standard 2.0 的代碼,同時還能夠得到 Visual Studio 和擴展插件較好的支持。

.NET Standard 和 .NET Core 項目在創建之時就已經是新的 csproj 格式了,但 .NET Framework 項目、UWP/WPF 項目依然使用舊風格的 csproj 文件。對於 .NET Framework 項目,可以通過 將 WPF、UWP 以及其他各種類型的舊 csproj 遷移成基於 Microsoft.NET.Sdk 的新 csproj - walterlv 一文進行遷移。不過對於 WPF/UWP 項目,根本就沒有跨多個 SDK 的必要,就不要改了

……

如果是新開項目——強烈建議先按照 .NET Standard 項目類型建好,再修改成多開發框架。

如何指定多個開發框架

只要是新 csproj 文件,指定多個開發框架真的是相當的簡單。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
  </PropertyGroup>
  <!-- 這個文件裏的其他內容 -->
</Project>

特別註意!!!TargetFramework 從單數形式變為了復數形式 TargetFrameworks!!!這個時候,TargetFramework 是編譯時自動指定的。

如果是對以上多框架的項目進行單元測試,考慮到編譯的目標平臺是多個的,單元測試項目也需要指定多個目標框架。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net471;netcoreapp2.0</TargetFrameworks>
    <IsPackable>false</IsPackable>
  </PropertyGroup>
  <!-- 這個文件裏的其他內容 -->
</Project>

多框架項目的坑以及如何避坑

微軟的官方文檔 How to: Configure Projects to Target Multiple Platforms - Microsoft Docs 中只說了如何指定多個目標框架,並沒有提及指定了多框架以後的坑。

如果多開發框架中包含了低版本的 .NET Framework,例如 4.0/4.5 等,那麽這些坑才比較容易凸顯——因為這些版本的 .NET Framework 與 .NET Standard 的第三方庫差異較大。所以,我們需要有方法來解決其第三方庫引用的差異。這時需要在 csproj 文件中指定包含條件。例如:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net471;netcoreapp2.0</TargetFrameworks>
    <OutputType Condition="‘$(TargetFramework)‘!=‘netcoreapp2.0‘">Exe</OutputType>
    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <!-- 這裏的引用是二者共有的 -->
  <ItemGroup>
    <PackageReference Include="MSTest.TestAdapter" Version="1.2.0" />
    <PackageReference Include="MSTest.TestFramework" Version="1.2.0" />
  </ItemGroup>

  <!-- 這裏的引用用於非 .NET Core 框架 -->
  <ItemGroup Condition="‘$(TargetFramework)‘!=‘netcoreapp2.0‘">
    <PackageReference Include="Xxx" Version="1.0.*" />
  </ItemGroup>

  <!-- 這裏的引用用於 .NET Core 框架 -->
  <ItemGroup Condition="‘$(TargetFramework)‘==‘netcoreapp2.0‘">
    <PackageReference Include="Yyy" Version="1.0.*" />
  </ItemGroup>

</Project>

在 dotnet-campus/MSTestEnhancer 項目中,只有 .NET Framework 4.5 才需要引用 System.ValueTuple,於是加上了 net45 條件判斷:

那段註釋的作用是告訴代碼分析工具 TargetFramework 是外部屬性,上下文環境中找不到這個屬性是正常的。

讓一個 csproj 項目指定多個開發框架[轉]