一、预处理指令:
解释:是在编译前由预处理器执行的命令,用于控制编译过程。这些命令以 #
开头,每行只能有一个预处理指令,且不能包含在方法或类中。
个人理解:就是游戏里面的备战阶段(不同对局,不同选英雄。。。)
1.#define
定义字符和 #undef取消定义字符
#define TEST
#undef TEST // 取消定义(删掉则输出"TEST 已定义")
#if TEST
Console.WriteLine("TEST 已定义");
#else
Console.WriteLine("TEST 未定义"); // 输出此行"TEST 未定义"
#endif
#define 宏常量与内置的 const 常量区别:
特性 #define 宏常量 const 常量
定义方式 定义条件符号,在编译前替换文本 语言关键字,声明为不可修改的变量
作用域 无作用域限制 遵循变量作用域(块、类作用域等)
类型安全 无类型检查,可能导致意外行为 有类型声明,编译器会进行类型检查
内存占用 无独立内存,直接替换为文本 可能占用内存(取决于编译器优化)
调试支持 调试时不可见(已替换为文本) 调试时可见(有独立符号)
灵活性 可定义复杂表达式或代码片段 仅能定义简单值
2.条件编译指令#if
, #else
, #elif
, #endif
#define DEBUG // 定义一个符号(通常在项目属性中设置)
#if !DEBUG
Console.WriteLine("不是DEBUG模式");//输出这一行
#elif DEBUG
Console.WriteLine("DEBUG模式");
#else
Console.WriteLine("其他模式");
#endif
配套使用规则
这些指令必须成对出现,形成一个完整的条件编译块:
#if
:开始条件编译块,检查符号是否定义。#elif
(可选):提供额外的条件分支。#else
(可选):定义默认分支(当所有条件都不满足时)。#endif
:结束条件编译块。
3.#error
错误和警告指令(可嵌套)
#if OLD_VERSION
#error 此代码需要更新到新版本
#else
Console.WriteLine("代码正常运行");
#endif
4.#warning 生成编译器警告信息
#warning 此方法已过时,需要重构
5.#region
:标记一个可折叠代码块的开始。#endregion
:标记一个可折叠代码块的结束。
#region Properties
Console.WriteLine("这一段是代码块1");
Console.WriteLine("这一段是代码块1");
Console.WriteLine("这一段是代码块1");
#endregion
#region Methods
Console.WriteLine("这一段是代码块2");
Console.WriteLine("这一段是代码块2");
Console.WriteLine("这一段是代码块2");
#endregion
6.#line显式指定编译器在生成错误或警告时报告的行号和文件名
#line
数字 "文件名"
#line default
恢复编译器使用实际的行号和文件名。
#line hidden
隐藏代码行(通常用于编译器内部实现,如生成的状态机代码)。
#line 10 "Template.tt"
public void GeneratedMethod() {
Console.WriteLine("Hello from generated code!");
}
#line default
7.#pragma 用于给编译器发送特殊指令,例如禁用或恢复特定的警告。
#pragma warning disable CS0168 // 禁用“变量未使用”的警告
int unusedVariable; // 不会触发CS0168警告
#pragma warning restore CS0168 // 恢复警告
int unusedVariable1; // 会触发CS0168警告
拓展:
#pragma checksum :校验
#pragma optimize
:控制代码优化(如 #pragma optimize "g"
, 启用尾调用优化)。
#pragma pack
:控制结构体的内存对齐(在C/C++中更常见,C#中较少使用)。
8.nullable 控制可空性上下文和注释,允许启用或禁用对可空引用类型的编译器检查。
string? nullableString = null; // 不会发出警告,默认启用可空注释
#nullable disable annotations
string? nullableString1 = null;//警告,因为可空注释已禁用
Console.WriteLine(nullableString.Length);//警告,出现空引用
#nullable disable
// 潜在的运行时错误
Console.WriteLine(nullableString1.Length);//不会发出警告,因为可空注释和警告都已禁用
#nullable enable
string anotherString = null; // 警告,空文本
Console.WriteLine(anotherString.Length); // 警告,因为可空注释和警告都启用
二、为什么要用预处理命令?
1.为什么要用这个?
1)不同环境编译不同代码(调试发布模式Debug,跨平台代码Windows,Linux,IOS)
2)快速定位:
a.标记暂时跳过的功能。
b.提醒团队成员完成关键代码
3)功能开关
#define NEW_UI
class Program {
static void Main() {
#if NEW_UI
ShowNewUI();
#else
ShowOldUI();
#endif
}
}
以 # 开始,不是语句,不以分号 ; 结束
4)提高可读性(用 #region
和 #endregion
折叠代码块,提升可读性。)
5) 灵活调试(#warning
和 #error
在编译时生成提示或错误)