当前位置: 首页 > news >正文

.NET/C# 项目如何优雅地设置条件编译符号?

条件编译符号指的是 Conditional Compilation Symbols。你可以在 Visual Studio 的项目属性中设置,也可以直接在项目文件中写入 DefineConstants 属性。

不过对于不同种类的项目,我建议使用不同的设置方法。本文将介绍如何设置条件编译符。


对于新旧格式的差别或者迁移,可以查看我的其他博客:

  • 理解 C# 项目 csproj 文件格式的本质和编译流程
  • 将 WPF、UWP 以及其他各种类型的旧 csproj 迁移成基于 Microsoft.NET.Sdk 的新 csproj

本文内容

      • 新格式推荐:在 csproj 文件中设置
      • 旧格式推荐:在 Visual Studio 项目属性中设置
      • 关于配置(Configuration)和条件编译符号(Conditional Compilation Symbols)

新格式推荐:在 csproj 文件中设置

在项目中设置 <DefineConstants /> 属性:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFrameworks>netcoreapp2.1;net47</TargetFrameworks>
    <DefineConstants>$(DefineConstants);WALTERLV</DefineConstants>
  </PropertyGroup>

</Project>

这里我使用字符串拼接的方式 $(DefineConstants);WALTERLV 来设置,这样可以把预设的那些条件编译符号保留,比如通常 Visual Studio 会帮你生成的 TRACE 条件编译符。

但即便你不做这种拼接也不用担心。因为基于框架或平台的条件编译符号是自动设置的。例如 NETCOREAPP2_1 等都是在你指定 DefineConstants 之后自动设置的。以下是 Microsoft.NET.Sdk 中的部分源码,可以证明这一点:

<PropertyGroup Condition="'$(DisableImplicitConfigurationDefines)' != 'true'">
  <ImplicitConfigurationDefine>$(Configuration.ToUpperInvariant())</ImplicitConfigurationDefine>
  
  <!-- Replace dashes and periods in the configuration with underscores.  This makes it more likely that
       the resulting compilation constant will be a valid C# conditional compilation symbol.  As the set
       of characters that aren't allowed is essentially open-ended, there's probably not a good way to
       fully sanitize the Configuration in MSBuild evaluation.  If the resulting string still isn't a
       valid conditional combilation symbol, then the compiler will generate the following error and
       the define will be ignored:
          warning MSB3052: The parameter to the compiler is invalid, '/define:0BAD_DEFINE' will be ignored.
       -->
  
  <ImplicitConfigurationDefine>$(ImplicitConfigurationDefine.Replace('-', '_'))</ImplicitConfigurationDefine>
  <ImplicitConfigurationDefine>$(ImplicitConfigurationDefine.Replace('.', '_'))</ImplicitConfigurationDefine>
  <DefineConstants>$(DefineConstants);$(ImplicitConfigurationDefine)</DefineConstants>
</PropertyGroup>
<PropertyGroup>
  <DefineConstants>$(DefineConstants);$(ImplicitFrameworkDefine)</DefineConstants>
</PropertyGroup>

旧格式推荐:在 Visual Studio 项目属性中设置

你可以在项目属性的“生成”页中找到条件编译符号的设置。

我自己用的 Visual Studio 是英文版的,但是也感谢小伙伴 林德熙 帮我截了一张中文版的图。

Conditional Compilation Symbols

条件编译符号

你需要特别注意:

  • 设置条件编译符号需要在各种配置下都设置,因为各种配置都是不一样的;具体来说是 Debug 下要设,Release 下也要设,x86 下要设,x64 下也要设。

关于配置(Configuration)和条件编译符号(Conditional Compilation Symbols)

你可能在你的代码中同时看到 Pascal 命名规则的 Debug 和全部大写的 DEBUG,或者看到 Release 和 RELEASE。这是两个不同的概念。

Debug 和 Release 的名称来自于配置(Configuration)。你的项目有 Debug 配置和 Release 配置,或者你自己定义的其他配置。你的项目编译过程默认根据 Debug 和 Release 配置做了很多不同的编译选项。例如 Debug 下会禁用优化而 Release 下会开启优化。

而 DEBUG 和 RELEASE 这样的全大写名称来自于条件编译符号(Conditional Compilation Symbols),是真正在 C# 代码中使用的符号。而这全大写符号的定义是分别在 Debug 和 Release 配置下设置了不同的值来实现的。

所以这两个是不同的概念,不要弄混淆了。

同时这也带来了一些命名建议:

  1. 条件编译符号使用全大写命名
    • 例如:DEBUG, RELEASE, NET47, NETCOREAPP2_1
  2. 配置使用 Pascal 命名
    • 例如:Debug, Release

我的博客会首发于 https://walterlv.com/,而 CSDN 和博客园仅从其中摘选发布,而且一旦发布了就不再更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://blog.csdn.net/wpwalter),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • 在 Roslyn 分析语法树时添加条件编译符号的支持
  • 自然码的形码
  • 出于迁移项目的考虑,GitHub 中 Fork 出来的项目,如何与原项目断开 Fork 关系?
  • 只需 5 秒钟,你就能取到 WPF 程序的超高分辨率超高清截图
  • 谨慎使用 FileInfo.Exists 实例方法,而是使用 File.Exists 静态方法替代
  • UWP 在 WebView 中执行 JavaScript 代码(用于模拟用户输入等)
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • int? 竟然真的可以是 null!.NET/C# 确定可空值类型 NullableT 实例的真实类型
  • Slack 开发入门之 Incoming Webhooks:往 Slack 的 Channel 中发消息
  • 三值 bool? 进行与或运算后的结果
  • 为什么我们不应该使用微信或者 QQ 作为团队协作的 IM 工具?
  • 通过重写预定义的 Target 来扩展 MSBuild / Visual Studio 的编译过程
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • C# 中委托实例的命名规则
  • 在 Target 中获取项目引用的所有依赖(dll/NuGet/Project)的路径
  • [笔记] php常见简单功能及函数
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • Angular Elements 及其运作原理
  • canvas 五子棋游戏
  • egg(89)--egg之redis的发布和订阅
  • ES6之路之模块详解
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • k个最大的数及变种小结
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • Vim Clutch | 面向脚踏板编程……
  • Vue 2.3、2.4 知识点小结
  • Wamp集成环境 添加PHP的新版本
  • 今年的LC3大会没了?
  • 前端工程化(Gulp、Webpack)-webpack
  • 前端路由实现-history
  • 我的zsh配置, 2019最新方案
  • ​Linux·i2c驱动架构​
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • (Matlab)基于蝙蝠算法实现电力系统经济调度
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (转)IOS中获取各种文件的目录路径的方法
  • (转载)Linux 多线程条件变量同步
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • *上位机的定义
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .NET 5种线程安全集合
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .Net环境下的缓存技术介绍
  • .net用HTML开发怎么调试,如何使用ASP.NET MVC在调试中查看控制器生成的html?
  • /usr/bin/perl:bad interpreter:No such file or directory 的解决办法
  • /var/log/cvslog 太大
  • @EnableConfigurationProperties注解使用
  • [ vulhub漏洞复现篇 ] GhostScript 沙箱绕过(任意命令执行)漏洞CVE-2019-6116
  • [【JSON2WEB】 13 基于REST2SQL 和 Amis 的 SQL 查询分析器
  • [C++]拼图游戏
  • [HDU]2161Primes
  • [HXPCTF 2021]includer‘s revenge
  • [IE6 only]关于Flash/Flex,返回数据产生流错误Error #2032的解决方式