C#中的预处理器指令详解
作者:junjie 发布时间:2022-05-04 21:22:32
目录
1. #define 和 #undef
2. #if、#elif、#else 和#endif
3. #warning 和 #error
4. #region 和#endregion
5. #line
6. #pragma
C#中有许多名为“预处理器指令”的命令。这些命令从来不会转化为可执行代码中的命令,但会影响编译过程的各个方面。
例如,使用预处理器指令可以禁止编译器编译代码的某一部分。如果计划发布两个版本的代码,即基本版本和拥有更多功能的企业版本,就可以使用这些预处理器指令。在编译软件的基本版本时,使用预处理器指令可以禁止编译器编译与额外功能相关的代码。
另外,在编写提供调试信息的代码时,也可以使用预处理器指令。实际上,在销售软件时,一般不希望编译这部分代码。
预处理器指令的开头都有符号#。
C++开发人员应知道,在C 和C++中预处理器指令非常重要,但是,在C#中,并没有那么多的预处理器指令,它们的使用也不太频繁。C#提供了其他机制来实现许多C++指令的功能,如定制特性。还要注意,C#并没有一个像C++那样的独立预处理器,所谓的预处理器指令实际上是由编译器处理的。
尽管如此,C#仍保留了一些预处理器指令名称,因为这些命令会让人觉得就是预处理器。
下面简要介绍预处理器指令的功能。
1. #define 和 #undef
#define 的用法如下所示: #define DEBUG
它告诉编译器存在给定名称的符号,在本例中是DEBUG。这有点类似于声明一个变量,但这个变量并没有真正的值,只是存在而已。
这个符号不是实际代码的一部分,而只在编译器编译代码时存在。在C#代码中它没有任何意义。
#undef 正好相反—— 它删除符号的定义: #undef DEBUG
如果符号不存在,#undef 就没有任何作用。同样,如果符号已经存在,则#define 也不起作用。必须把#define 和#undef 命令放在C#源文件的开头位置,在声明要编译的任何对象的代码之前。
#define 本身并没有什么用,但与其他预处理器指令(特别是#if)结合使用时,它的功能就非常强大了。
这里应注意一般C#语法的一些变化。预处理器指令不用分号结束,一般一行上只有一条命令。这是因为对于预处理器指令,C#不再要求命令使用分号进行分隔。如果它遇到一条预处理器指令,就会假定下一条命令在下一行上。
2. #if、#elif、#else 和#endif
这些指令告诉编译器是否要编译某个代码块。考虑下面的方法:
int DoSomeWork(double x)
{
// do something
#if DEBUG
Console.WriteLine("x is " + x);
#endif
}
这段代码会像往常那样编译,但Console.WriteLine 命令包含在#if 子句内。
这行代码只有在前面的#define 命令定义了符号DEBUG 后才执行。
当编译器遇到#if 语句后,将先检查相关的符号是否存在,如果符号存在,就编译#if 子句中的代码。否则,编译器会忽略所有的代码,直到遇到匹配的#endif 指令为止。
一般是在调试时定义符号DEBUG,把与调试相关的代码放在#if 子句中。在完成了调试后,就把#define 语句注释掉,所有的调试代码会奇迹般地消失,可执行文件也会变小,最终用户不会被这些调试信息弄糊涂(显然,要做更多的测试,确保代码在没有定义DEBUG 的情况下也能工作)。
这项技术在C 和C++编程中十分常见,称为条件编译(conditional compilation)。
#elif (=else if)和#else 指令可以用在#if 块中,其含义非常直观。也可以嵌套#if 块:
#define ENTERPRISE
#define W2K
// further on in the file
#if ENTERPRISE
// do something
#if W2K
// some code that is only relevant to enterprise
// edition running on W2K
#endif
#elif PROFESSIONAL
// do something else
#else
// code for the leaner version
#endif
与C++中的情况不同,使用#if 不是有条件地编译代码的唯一方式,C#还通过Conditional 特性提供了另一种机制。
#if 和#elif 还支持一组逻辑运算符“!”、“==”、“!=”和“||”。如果符号存在,就被认为是true,否则为false,例如:
#if W2K && (ENTERPRISE==false) // if W2K is defined but ENTERPRISE isn't
3. #warning 和 #error
另两个非常有用的预处理器指令是#warning 和#error,当编译器遇到它们时,会分别产生警告或错误。如果编译器遇到#warning 指令,会给用户显示#warning 指令后面的文本,之后编译继续进行。如果编译器遇到#error 指令,就会给用户显示后面的文本,作为一条编译错误消息,然后会立即退出编译,不会生成IL 代码。
使用这两条指令可以检查#define 语句是不是做错了什么事,使用#warning 语句可以提醒自己执行某个操作:
#if DEBUG && RELEASE
#error "You've defined DEBUG and RELEASE simultaneously!"
#endif
#warning "Don't forget to remove this line before the boss tests the code!"
Console.WriteLine("*I hate this job.*");
4. #region 和#endregion
#region 和#endregion 指令用于把一段代码标记为有给定名称的一个块,如下所示。
#region Member Field Declarations
int x;
double d;
Currency balance;
#endregion
这看起来似乎没有什么用,它不影响编译过程。这些指令的优点是它们可以被某些编辑器识别,包括Visual Studio .NET 编辑器。这些编辑器可以使用这些指令使代码在屏幕上更好地布局。
5. #line
#line 指令可以用于改变编译器在警告和错误信息中显示的文件名和行号信息。这条指令用得并不多。
如果编写代码时,在把代码发送给编译器前,要使用某些软件包改变输入的代码,就可以使用这个指令,因为这意味着编译器报告的行号或文件名与文件中的行号或编辑的文件名不匹配。
#line 指令可以用于还原这种匹配。也可以使用语法#line default 把行号还原为默认的行号:
#line 164 "Core.cs" // We happen to know this is line 164 in the file
// Core.cs, before the intermediate
// package mangles it.
// later on
#line default // restores default line numbering
6. #pragma
#pragma 指令可以抑制或还原指定的编译警告。与命令行选项不同,#pragma 指令可以在类或方法级别执行,对抑制警告的内容和抑制的时间进行更精细的控制。
下面的例子禁止“字段未使用”警告,然后在编译MyClass 类后还原该警告。
#pragma warning disable 169
public class MyClass
{
int neverUsedField;
}
#pragma warning restore 169
感谢大家收看,谢谢亲们了。


猜你喜欢
- 本文实例讲述了Android编程入门之HelloWorld项目目录结构。分享给大家供大家参考,具体如下:我们介绍了如何搭建Android开发
- 本文实例为大家分享了android短信管理器SmsManager的具体代码,供大家参考,具体内容如下需要注册的权限<uses-perm
- 前言在机器学习中,卷积神经网络是一种深度前馈人工神经网络,已成功地应用于图像识别。目前,很多的车牌识号识别,人脸识别等都采用卷积神经网络,可
- 一、什么是HTTP协议HTTP是hypertext transfer protocol(超文本传输协议)的简写,它是TCP/IP协议的一个应
- MainActivity如下:package cc.ab;import android.os.Bundle;import android.p
- 本文以在chart控件上和窗体上画矩形为例子讲述了C# GDI在控件上绘图的方法。分享给大家供大家参考。具体方法如下:具体的实现方法就不多解
- 如果我们有这样一个应用场景:WidgetA执行点击之后将数据通过widgetB传递到其下的widgetC。通常可以通过设置构造函数,传递对应
- 一、背景单机节点下,WebSocket连接成功后,可以直接发送消息。而多节点下,连接时通过nginx会代理到不同节点。假设一开始用户连接了n
- 本文实例为大家分享了C#端口扫描器的编写代码,供大家参考,具体内容如下一、项目设计新建项目整体设计最终设计二、单线程1.代码编写button
- 本文实例为大家分享了Java实现简单抽牌游戏的具体代码,供大家参考,具体内容如下Main类package com.company;impor
- 随着互联网的蓬勃发展,越来越多的互联网企业面临着用户量膨胀而带来的并发安全问题。本文着重介绍了在java并发中常见的几种锁机制。1.偏向锁偏
- 首先 下载 jedis.jar包然后再 工程设置里面找到Libraries,点击+。添加下载好的jedis.jar包。点击OK退出即可创建J
- 区别1.使用范围和规范不同filter是servlet规范规定的,只能用在web程序中. * 即可以用在web程序中, 也可以用于appli
- Java选择的泛型类型叫做类型擦除式泛型。什么是类型擦除式泛型呢?就是Java语言中的泛型只存在于程序源码之中,在编译后的字节码文件里,则全
- 在 Java 中将 Object 转换为 Int我们可以使用 Object 类来引用我们在 Java 中不知道其类型的任
- 麦洛开通博客以来,有一段时间没有更新博文了.主要是麦洛这段时间因项目开发实在太忙了.今天周六还在公司加班,苦逼程序猿都是这样生活的.今天在做
- 1、两个相关概念:Git和githubGit是一个开源的分布式 版本控制 系统,用以有效、高速的处理从很小到非常大的项目版本管理。 Git
- 先看一下Android悬浮按钮点击回到顶部的效果:FloatingActionButton是Design Support库中提供的一个控件,
- 一个打砖块游戏算法,供大家参考,具体内容如下这里有一个打砖块游戏:小明面前有很多砖块,每个砖块上有一个字符,小明每击中一个砖块,会产生一个分
- Android本地存储SharedPreferences详解存储位置SharedPreferences数据保存在: /data /data/