预处理指令

  1. 预处理指令
    • 源代码指定了程序的定义
    • 预处理指令指示编译器如何处理源代码
    • 在C/C++中有实际的预处理阶段,预处理程序遍历源代码并为之后的编译阶段准备文本输出流
    • C#中没有实际的预处理程序,预处理指令由编译器来处理
  2. 基本规则
    • 预处理指令必须和C#代码在不同的行
    • 不需要以分号结尾
    • 必须以#开头,但是#前可以有空格,#和指令直接可以有空格
    • 允许行尾注释,,不允许分隔符注释(即允许// ...但是不允许/* ... */
  3. 预处理指令类型
    • #define IDENTIFIER:定义编译符
    • #undef IDENTIFIER:取消定义编译符
    • #if EXPRESSION:如果EXPRESSION为true,则编译下面的片段
    • #elif EXPRESSION:如果前面的#if为false且当前的EXPRESSION为true,则编译下面的片段
    • #else:如果之前的#if或者#elif为false,则编译下面的片段
    • #endif:标记一个#if片段的结构
    • #region NAME:标记一段代码的开始,没有效果
    • #endregion NAME:标记一段代码的结束,没有效果
    • #warning MESSAGE:显式编译时的警告消息
    • #error MESSAGE:显式编译时的错误消息
    • #line INDICATOR:修改在编译器消息中显示的行数
    • #pragma TEXT:指定有关程序上下文的信息
  4. #define#undef
    • 可以是除了true或false以外的任意标识符,包括C#关键字和在C#代码中声明的标识符
    • 没有值,和C/C++不同,不表示字符串
    • 只能在源文件的最前面,也就是任何C#代码之前使用,不能放在C#代码开始之后
    • 编译符号被限制在单个文件
    • 允许重复定义
  5. 条件编译
    • 允许根据某个编译符号是否被定义标注一段代码是否被编译或者跳过
    • 条件是一个返回true或false的简单表达式
      • 可以由单个编译符号、符号表达式或操作符组成,可以使用括号
      • true和false也可以直接使用
    • 条件编译结构
      • #if#endif必须配对使用,#elif#else可根据条件选择
  6. 诊断指令
    • 产生用户自定义的编译时的警告以及错误信息
      • #warning MESSAGE
      • #error MESSAGE
      • 其中MESSAGE是自定义字符串代表错误信息,但是不需要加引号
    • 当编译器遇到诊断指令时,会输出相关的消息,会和任何编译器产生的警告和错误列在一起
  7. 行号指令
    • 行号指令可以做很多事情例如
      • 改变由编译器警告和错误消息报告的出现行数
      • 改变被编译源文件的文件名
      • 对交互式调试器隐藏一些行
    • 语法:
    • #line INTEGER:加整数可以设置下一行值为整数的行的行号
    • #line "FILENAME":改变外观文件名,双引号是必须的
    • #line default:重新保存实际的行号和文件名,得到真实的行号和文件名
    • #line hidden:在断点调试器隐藏代码
    • #line:停止在调试器隐藏代码
  8. 区域指令
    • 允许有选择地命名一段代码
      • #region NAME被放在在希望标注代码段之前,NAME是可选字符串文本不加引号
      • 在代码段结束后用#endregion标记终止
    • 尽管会被编译器忽略,但是可以被IDE使用如折叠代码
  9. #pragma warning指令
    • 允许关闭及重新打开警告信息
    • 举例
      • public struct Vector2Int {	// 随便提供了一个类
            public int x, y;
            public static Vector2Int zero {
                get {
                    return new Vector2Int(0, 0);
                }
            }
            public Vector2Int(int x, int y) {
                this.x = x;
                this.y = y;
            }
            public static bool operator == (Vector2Int a, Vector2Int b) {
                return a.x == b.x && a.y == b.y ;
            }
            public static bool operator != (Vector2Int a, Vector2Int b) {
                return a.x != b.x || a.y != b.y ;
            }
        }
        
      • 警告信息如下:
        • “Vector2Int”定义运算符 == 或运算符 !=,但不重写 Object.Equals(object o) [Test] csharp(CS0660) [55, 15]
          “Vector2Int”定义运算符 == 或运算符 !=,但不重写 Object.Equals(object o) [Test] csharp(CS0660) [55, 15]
          
      • 在文件开头加上#pragma warning disable CS0660, CS0661可以使编译器忽略这两条警告不产生警告信息(实际开发的时候除非没必要建议解决掉所有警告)
    • 要关闭警告,可以使用#pragma warning disable XXX, XXX用逗号分隔希望关闭的警告数
    • 要打开警告,可以使用#pragma warning restore XXX, XXX
    • 如果省略警告数,会应用于所有警告