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

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

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


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

 

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

本文內容

新 csproj 文件

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

使用共享項目的方式則是直接共享了源碼,只要在目標項目中指定了條件編譯符,那麼源碼便能針對各類不一樣的目標框架進行分別編譯。但缺點是對擴展插件的支持較差(多是由於擴展插件難以判斷項目的真實開發框架),並且 Visual Studio 自己對它的支持也有 BUG(例如切換編寫文件所屬的項目常常會失敗)。ide

新的 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 的必要,就不要改了……post

若是是新開項目——強烈建議先按照 .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 是外部屬性,上下文環境中找不到這個屬性是正常的。

相關文章
相關標籤/搜索