讓一個 csproj 項目指定多個開發框架[轉]
原貼: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 項目指定多個開發框架[轉]