2.1.5 C#8.0教程 - 预处理指令 预处理指令的位置
liebian365 2024-10-18 09:35 41 浏览 0 评论
如果你熟悉 C语言 或它的直系衍生语言,你一定了解预处理器的基本概念。那么 C# 是否提供了预处理器?结论是:它没有单独的预处理阶段,也不提供宏。然而,它确实有一些类似于 C语言 预处理器提供的指令,尽管它的选择非常有限。尽管 C# 不像 C 一样有完整的预处理阶段,但是这些被称为预处理指令。本课将会提到一些常用的指令。
- 编译符号
- #error 与 #warning
- #line
- #pragma
- #nullable
- #region and #endregion
编译符号
C# 提供了一个 #define 指令,可以让你定义编译符号。这些符号通常与 #if 指令一起使用,以不同的方式针对不同的情况编译代码。例如,你可能希望某些代码只出现在调试中,或者你可能需要在不同的平台上使用不同的代码来实现特定的效果。通常,你不会使用 #define 指令,但更常见的是通过编译器构建设置来定义编译符号。要对此进行控制,可以直接打开 .csproj 项目文件,在 PropertyGroup 中的 DefineConstants 元素中定义需要的值。
.NET SDK 定义了某些默认符号。它支持两种配置:调试Debug 和 发布Release。它在调试配置中定义 DEBUG 编译符号,而在发布中定义了 RELEASE。在两种配置中定义了一个两者共有的称为 TRACE 的符号。某些项目类型使用额外的符号。例如,针对 .NET Standard 2.0 将同时定义NETSTANDARD 和 NETSTANDARD2_0。
编译符号通常与 #if、#else、#elif 和 #endif 指令一起使用(#elif是else if的缩写)。例5.1 使用其中一些指令来确保某些代码行只在调试版本中编译。(你还可以编写#if false来完全防止代码段被编译。这通常只是作为一种临时措施,是注释的替代方法,避免了试图嵌套注释时的词汇陷阱。)
// 示例 5.1
static void Main(string[] args)
{
#if RELEASE
Console.WriteLine("RELEASE ...");
#endif
#if DEBUG
Console.WriteLine("DEBUG ...");
#endif
}
c#提供了一种更微妙的机制来支持这类事情,称为条件方法。编译器识别.NET类库定义的称为ConditionalAttribute的属性,并为其提供特殊的 编译时compile-time 行为。你可以给任何方法用此属性注释。例5.2 使用它表示只有在定义了调试编译符号时才应该使用带注释的方法。
// 示例 5.2
static void Main(string[] args)
{
ShowDebugInfo();
ShowReleaseInfo();
}
[System.Diagnostics.Conditional("DEBUG")]
static void ShowDebugInfo()
{
Console.WriteLine("Conditional DEBUG ...");
}
[System.Diagnostics.Conditional("RELEASE")]
static void ShowReleaseInfo()
{
Console.WriteLine("Conditional RELEASE ...");
}
注意对比图2 、图3的两个条件方法,一个是在 Debug 阶段运行的,一个是在 Release 阶段运行的。
特别要注意输出面板,分别输出了 “Conditional DEBUG ...” 和 “Conditional RELEASE ...”。说明条件方法在起作用。
另外要特别理解的是,如果您编写的代码调用了这样注释的方法,c#编译器将在没有定义相关符号的编译中忽略该调用。因此,如果你编写代码来调用这两个 ShowDebugInfo / ShowReleaseInfo 方法,编译器会在编译中删除另外一个调用方法,但不会使用指令使代码混乱。
.NET类库中的 Debug类 和 Trace类 在System.Diagnostics命名空间使用此特性。Debug类提供了各种以调试编译符号为条件的方法,而Trace类有以跟踪为条件的方法。如果保留新C#项目的默认设置,那么通过Trace类生成的任何诊断输出都将在调试和发布版本中可用,但是调用Debug类上的方法的任何代码都不会编译到发布版本中。
#error 与 #warning
C# 允许您使用 #error 和 #warning 指令来选择生成编译器错误或警告。这些通常在条件区域内使用,如例2-30所示,当然一个无条件执行的 #warning 可以用来提醒自己还没有编写一些特别重要的代码。
// 示例 5.3
static void Main(string[] args)
{
#warning 当您运行此代码后,您有权保持沉默,您所说的一切将会作为呈堂证供!
#error 停止交易,有内鬼!
}
如图4.所示,#warning 会导致出现警告提示,但仍会继续编译过程。但 #error 除了会出现错误提示外,还会导致编译失败,或者称 build 错误,修复后才能继续。
#line
在生成的代码中,#line指令非常有用。当编译器生成错误或警告时,它通常会声明问题发生的位置,提供文件名、行号和该行内的偏移量。但是,如果问题代码是使用其他文件作为输入自动生成的,并且其他文件包含问题的根本原因,那么在输入文件中报告错误可能比在生成的文件中报告错误更有用。一个#line指令可以指示c#编译器就像错误发生在指定的行号上一样,也可以选择像错误发生在一个完全不同的文件中一样。例5.4 展示了如何使用它。指令后的错误将被报告,好像它来自一个名为footbar.cs的文件的第999行。
static void Main(string[] args)
{
Inttt x;
#line 999 "footbar.cs"
Inttt x;
}
如图5.所示,虽然 Program.cs 的第9行、第11行出现两处明显的语法错误。但提示出现的文件及所在位置却明显不同。请特别关注橙色箭头与白色箭头所示的区别。
另外,文件名部分是可选的,行号也可以伪造,一切都只是注释。您可以通过编写#line default来告诉编译器恢复报告正常的警告和错误状态,否则后面出现的一切错误都会以这个基础继续。
#pragma
#pragma 指令提供了两个特性:它可以用来禁用选定的编译器警告,还可以用来覆盖编译器放入它生成的包含调试信息的 .pdb 文件中的校验和值。这两种方法主要是为代码生成场景设计的,不过它们有时也可以用于禁用普通代码中的警告。例5.5展示了如何使用 #pragma 来防止您声明但没有继续使用的变量而弹出的警告信息。
static void Main(string[] args)
{
int x;
#pragma warning disable CS0168
int y;
}
如图6.所示,在启用 #pragma 指令前,会提示警告变量x未使用。但在启用后,变量y的警告提示未显示。
通常应该避免禁用警告。此特性在生成的代码中非常有用,因为代码生成通常会创建不经常使用的项,而pragmas可能提供了获得干净编译的唯一方法。但是当您手工编写代码时,通常应该能够首先避免警告。
总的来说,如果不是强迫症患者,请勿使用该功能。当然,#pragmas 还有一些其他的能力,比如说为 C# 8.0 中添加的新特性 nullable 等。但对于初学者来说,好像暂时无所谓……但毕竟课题是 C# 8.0 教程,所以我们不得不说一些关于 8.0 的新知识。如下:
#nullable
C# 8.0添加了一个新的指令 #nullable,它允许对可空的注释上下文进行精细控制。这是之后章节中描述的可空引用特性的一部分。(这与之前 #pragmas 中描述的 nullable 警告控件没有重叠,因为我们控制是否启用了nullability注释,与是否启用了与这些注释关联的警告无关)
#region and #endregion
最后,我们有两个不做任何事情的预处理指令。如果你写了#region指令,编译器做的唯一一件事就是确保它们有或者响应#endregion指令。不匹配会导致编译器错误,但是编译器会忽略正确配对的#region和#endregion指令。区域可以嵌套。
这些指令的存在完全是为了便于选择识别它们的文本编辑器。Visual Studio 或 Visual Studio Code 等 C#编辑器使用这组指令可将其包含的代码部分折叠为屏幕上的一行。c#编辑器自动允许扩展和折叠某些特性,比如类定义、方法和代码块(称为outline的特性)。如果您使用这两个指令定义区域,它还将允许扩展和折叠这些区域。
如果将鼠标悬停在折叠区域上,Visual Studio Code 等多数C#编辑器将显示工具提示,显示该区域的内容。
如图7.所示,因为增加了一组 #region 指令,则会在行号后面自动增加出 折叠按钮 (红色箭头所示),会将从 #region 开始,到 #endregion 结束的代码块折叠起来。
虽然代码块 { } 符号也可实现折叠效果,但区别在于,编译器会完全忽略 #region,但 { } 对于编译器来说是有意义的,所以不是完全等同。
本课小结
本课所提到预编译指令,不能给我们的程序带来更多的功能,也无法提高代码执行效率。更多是为代码编辑者使用。大家了解即可,未来读程序时肯定会遇到,可以再来细读。
下节开始数据类型……
相关推荐
- 4万多吨豪华游轮遇险 竟是因为这个原因……
-
(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...
- “菜鸟黑客”必用兵器之“渗透测试篇二”
-
"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...
- 科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白
-
作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...
- 麦子陪你做作业(二):KEGG通路数据库的正确打开姿势
-
作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...
- 知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势
-
智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...
- 每日新闻播报(September 14)_每日新闻播报英文
-
AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...
- 香港新巴城巴开放实时到站数据 供科技界研发使用
-
中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...
- 5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper
-
本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...
- Qt动画效果展示_qt显示图片
-
今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...
- 如何从0到1设计实现一门自己的脚本语言
-
作者:dong...
- 三年级语文上册 仿写句子 需要的直接下载打印吧
-
描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...
- C++|那些一看就很简洁、优雅、经典的小代码段
-
目录0等概率随机洗牌:1大小写转换2字符串复制...
- 二年级上册语文必考句子仿写,家长打印,孩子照着练
-
二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)