原贴: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 文件

如何组织一个同时面向 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 项目指定多个开发框架[转]的更多相关文章

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

    可移植类库.共享项目..NET Standard 项目都能够帮我们完成跨多个 .NET SDK 的单一项目开发,但它们的跨 SDK 开发都有些限制.现在,我们又有新的方式能够跨多个 .NET SDK ...

  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. CentOS 下 LNMP 环境配置

    安装配置 Nginx 安装配置 MySQL 安装配置 PHP Nginx 与 PHP-FPM 集成 环境配置验证   LNMP 环境代表 Linux 系统下 Nginx + MySQL + PHP 网 ...

  2. oracle 10g函数大全--数值型函数

    ABS(x) [功能]返回x的绝对值 [参数]x,数字型表达式 [返回]数字 [示例] select abs(100),abs(-100) from dual; sign(x) [功能]返回x的正负值 ...

  3. IntelliJ IDEA java开发 WebService

    测试的功能是通过访问solr服务器,获取相关信息,然后以webservice的形式供客户端访问来获取数据.通过查询资料,现在把过程记录如下: 1.环境 IntelliJ IDEA 2017.2.6 J ...

  4. 绿化和卸载 DOS 批处理

    @ECHO OFF&PUSHD %~DP0 &TITLE 绿化和选项 mode con cols= lines= color 2F Rd >NUL Md >NUL||(Ec ...

  5. JDK自带内存及线程分析工具

    转载:http://blog.csdn.net/kimylrong/article/details/50970493 查询.监控.分析Java应用程序的时候,我们关注的点主要集中在资源利用,比如CPU ...

  6. 二叉树(9)----打印二叉树中第K层的第M个节点,非递归算法

    1.二叉树定义: typedef struct BTreeNodeElement_t_ { void *data; } BTreeNodeElement_t; typedef struct BTree ...

  7. 数据库连接dbcp$c3p0

    <?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <!-- 这是默认配置信 ...

  8. Android资源图片读取机制

    在新建一个Android项目时.在res目录下会自己主动生成几个drawable目录,drawable-ldpi,drawable-mdpi,drawable-hdpi,一直以来都对此不太清楚.图片应 ...

  9. iDempiere VS ADempiere

    怀揣着为中小企业量身定做一整套开源软件解决方案的梦想开始了一个网站的搭建.http://osssme.org/ 第三篇:iDempiere VS ADempiere 一直以来,什么谁谁谁VS谁谁谁的, ...

  10. AL2018届校招笔试——自然语言处理

    [单选40min+在线编程80min] 单选 1.以下进程的哪些行为不会导致操作系统向该进程发送一个信号?() A. 程序终止退出 B. 访问了一个非法的内存地址 C. 一个该程序正在监听的socke ...