原贴: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
在 如何组织一个同时面向 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
是外部属性,上下文环境中找不到这个属性是正常的。