可移植类库、共享项目、.NET Standard 项目都能够帮我们完成跨多个 .NET SDK 的单一项目开发,但它们的跨 SDK 开发都有些限制。现在,我们又有新的方式能够跨多个 .NET SDK 开发了,这就是使用新的 csproj 文件格式。


看看拥有多个开发框架的项目长什么样吧!


▲ 多 SDK 项目

是不是很激动?

 

新 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 文件迁移成新样式的 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>

参考资料

让一个 csproj 项目指定多个开发框架的更多相关文章

  1. 让一个 csproj 项目指定多个开发框架[转]

    原贴:https://walterlv.gitee.io/post/configure-projects-to-target-multiple-platforms.html 可移植类库.共享项目..N ...

  2. Log4J是Apache组织的开源一个开源项目,通过Log4J,可以指定日志信息输出的目的地,如console、file等。Log4J采用日志级别机制,请按照输出级别由低到高的顺序写出日志输出级别。

    Log4J是Apache组织的开源一个开源项目,通过Log4J,可以指定日志信息输出的目的地,如console.file等.Log4J采用日志级别机制,请按照输出级别由低到高的顺序写出日志输出级别. ...

  3. .net core 第一个mvc项目目录结构简析

    创建项目的命令     首先来认识一下创建项目可使用的各种命令,.NETCore 的命令都以 dotnet 打头,这很好理解,输入 dotnet xxx,就是执行环境变量指向的 C:\Program ...

  4. Mbp,一个用于学习.net core的开发框架

    Mbp(https://github.com/mbpframework/Mbp)是一个.net core 3的企业级web开发框架,是我个人用于学习.net core而发起的一个开源项目.这个借鉴了国 ...

  5. 用struts2标签如何从数据库获取数据并在查询页面显示。最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变量。

    最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变 ...

  6. ReactNative新手学习之路02第一个RN项目

    开始第一个RN项目(iOS版)我的电影列表0.1版,后面做列表版 打开上一节项目 index.ios.js,android打开index.android.js.我这里使用的是Atom编辑器,你也可以使 ...

  7. [front]有效开展一个前端项目

    今天的前端如果没有用到 npm,效率是比较低的:所以要从使用的工具来讲. 1. 一切都依赖于 nodejs: 下载一个 linux 的源码包就可以开始安装了. $ wget https://nodej ...

  8. ASP.NET Core 1.0 入门——了解一个空项目

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  9. eclipes创建一个web项目web.xml不能自动更新的原因(web.xml和@WebServlet的作用)

    在eclipse中创建一个Web项目的时候,虽然有web.xml生成,但是再添加Servlet类文件的时候总是看不见web.xml的更新,所以异常的郁闷!上网查了查,原来我们在创建Web项目的时候,会 ...

随机推荐

  1. Eclipse安卓项目导入android.support.design报错的解决办法

    导入android.support.design出错:1.项目除了需要依赖appcompat_v7包外还要design包2.design包就是在安卓sdk下Extras中的android.suppor ...

  2. 机器学习笔记—K-均值聚类

    在聚类问题中,给定训练集 {x(1),...,x(m)},要把数据分成内聚的“簇”.这里 x(i)∈R,没有 y(i).所以,这是一个无监督学习问题. k-均值聚类算法如下: 1.随机初始化簇中心 μ ...

  3. FlatBuffer入门笔记

    FlatBuffer入门笔记 1 flatbuffer资料 flatbuffer下载地址:https://github.com/google/flatbuffers flatbuffer官方使用文档: ...

  4. ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków

    ACM ICPC Central Europe Regional Contest 2013 Jagiellonian University Kraków Problem A: Rubik’s Rect ...

  5. mysql数据库开放远程连接的方法

    web与mysql数据库分离开来是一个不错的选择,避免因为大量的数据库查询占用CPU而使web资源不足,同时可以使web服务器的资源尽最大的提供浏览服务,而数据库服务器单独的只处理数据库事物. 适用范 ...

  6. WebAPI项目 IHttpActionResult不识别解决办法

    转自:http://blog.csdn.net/nnnnnbody/article/details/16945253 使用ASP.NET Web API构造基于restful风格web service ...

  7. js今日小结—Ajax、前端安全、GET&POST、闭包、HTTPS

    HTTPS HTTP+加密(SSL.TLS)+认证+完整性保护 = HTTPS: GET和POST的区别 get拉取数据,post传输数据 get请求能被浏览器主动缓存,post不会(除非手动) ge ...

  8. linux禁止ping

    1.临时禁止PING操作的命令为:#echo 1>/proc/sys/net/ipv4/icmp_echo_ignore_all 2.永久禁止PING配置方法 /etc/sysctl.conf  ...

  9. jmeter-03 JMeter + Jenkins 集成

    一.准备JMeter 测试计划 mock_api.jmx 接口准备:http://10.1.102.75:8000/mock/api/jmeter 二.jenkins 插件准备  Performanc ...

  10. Java对象的初始化顺序

    new一个对象时,该对象的初始化顺序如下 : 父类中的静态成员变量 父类中的静态代码块 子类中的静态成员变量 子类中的静态代码块 父类中的非静态变量 父类中的非静态代码块 父类构造函数 子类中的非静态 ...