C# 中的预处理器指令
介绍
在本指南中,您将了解预处理器在 C# 中的工作原理。我们将首先熟悉预处理器的概念,然后了解该概念如何融入语言本身。稍后,我们将介绍最常见的预处理器指令和一些实际示例。
预处理器
这个概念属于编译语言的范畴。编译语言是一种将高级代码(如 C# 或 C)在编译器的帮助下转换为机器代码的语言。编译器是不同制造商架构之间的抽象层,它知道如何将代码块转换为不同架构(如Intel或AMD处理器指令)。预处理器本身不会生成最终的机器代码。顾名思义,它只是为编译器预处理代码。它包含预先评估并对编译过程产生影响的指令。预处理器通常被视为与编译器分开的实体。根据语言的不同,预处理器的范围从相当简单到更复杂。
C# 中的处理器被认为非常简单,提供的功能比 C 编程语言中的处理器要少。
C# 中生成可执行应用程序的工作流程如下所示。
预处理器指令
这些指令必须以#符号开头,并且由于它们不是语句,因此它们在行尾不包含通常的分号,所以它们以新行终止。
这是预处理器的列表。
- #如果
- #别的
- #elif
- #结束
- #定义
- #undef
- #警告
- #错误
- #线
- #地区
- #结束区域
- #pragma
- #pragma 警告
- #pragma 校验和
现在我们来看看这些指令的含义。如果你熟悉bash脚本或C语言编程,这些概念一定让你印象深刻。
#如果,#否则,#elif,#结束
这些是条件指令。#if指令始终包含在#endif指令中,您可以在两者之间定义不同的构造。这些可以是基于参数的其他组件的条件初始化,或者基本上是应用程序所需的任何内容。您可以使用#else和#elif条件进一步微调您的构造。
您可以使用==或!=运算符来仅测试true或false的布尔值。
Let's see an example of this in action. The assumption from now on is that you have Visual Studio installed.
Begin with the following code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Pluralsight
{
class Program
{
static void Main(string[] args)
{
#if DEBUG
System.Console.WriteLine("Preprocessors are cool, running in Debug mode!");
#else
System.Console.WriteLine("Preprocessors are still cool, even if you are not debugging!");
#endif
System.Console.ReadKey();
}
}
}
You have two options to build and run the solution: you either run it in RELEASE mode or DEBUG mode. By default the DEBUG mode is run, and this output is produced.
Preprocessors are cool, running in Debug mode!
If you switch this to run in RELEASE mode, you get the following output.
Preprocessors are still cool, even if you are not debugging!
Note how extra functionality can be added to our application and is dynamically picked up during preprocessing.
#define, #undef
These directives can be used to define and undefine directives for the preprocessors. The most common use case for this is when you would like to define extra conditions for the compilation itself. This is usually done in tandem with the #if directive to provide a more sophisticated compiling experience. If you do not want to litter your code with the #define directive, you have the option to use the -define argument to the compiler to do the same. This really depends on your application and situation. Both have their advantages and disadvantages.
Our task is to create a Tier-based build configuration with the help of preprocessors. We have three different tiers: PROD, TEST, and DEV. The rules say that we do NOT want TRACE and DEBUG enabled when building for PROD. We only want DEBUG enabled when building for TEST, and we want both DEBUG and TRACE enabled when building for DEV.
Here is our demonstration code for that.
#define DEV
#if PROD
#undef DEBUG
#undef TRACE
#endif
#if TEST
#undef TRACE
#endif
#if DEV
#define DEBUG
#define TRACE
#endif
using System;
namespace Pluralsight
{
class Program
{
static void Main(string[] args)
{
#if PROD
System.Console.WriteLine("Target is PROD!");
#elif TEST
System.Console.WriteLine("Target is TEST");
#elif DEV
System.Console.WriteLine("Target is DEV");
#endif
#if DEBUG
System.Console.WriteLine("DEBUG is ENABLED!");
#else
System.Console.WriteLine("DEBUG is DISABLED!");
#endif
#if TRACE
System.Console.WriteLine("TRACE is ENABLED!");
#else
System.Console.WriteLine("TRACE is DISABLED!");
#endif
System.Console.ReadKey();
}
}
}
There is a rule which says you cannot #define or #undef directives after the first token in a line. This only means you need to put all your directives regarding this before the rest of the code.
Upon executing the code as it is now with DEV settings, you will see the following output produced.
Target is DEV
DEBUG is ENABLED!
TRACE is ENABLED!
If you swap out the first line to #define TEST, you will see the following output.
Target is TEST
DEBUG is ENABLED!
TRACE is DISABLED!
Swapping out to #define PROD will produce the following output.
Target is PROD!
DEBUG is DISABLED!
TRACE is DISABLED!
This can be further improved by removing the first like and then simply passing the -define <Tier> as command line argument to the compiler.
#warning, #error
这些指令允许您发出警告或终止错误消息。发出警告时,它只会出现在控制台日志中,但错误级别会中断编译。当您想警告用户有关过时的依赖项或防止构建由您的自定义错误消息终止的不完整解决方案时,这非常有用。
让我们修改一下前面的例子,这样如果脚本中没有定义Tier或者将其作为硬编码参数传递,编译过程就会中断!
#if PROD
#undef DEBUG
#undef TRACE
#endif
#if TEST
#undef TRACE
#endif
#if DEV
#define DEBUG
#define TRACE
#endif
#if !PROD && !TEST && !DEV
#error Cannot compile as the Tier is not specified
#else
#warning Running with hard coded Tier information
#endif
using System;
namespace Pluralsight
{
class Program
{
static void Main(string[] args)
{
#if PROD
System.Console.WriteLine("Target is PROD!");
#elif TEST
System.Console.WriteLine("Target is TEST");
#elif DEV
System.Console.WriteLine("Target is DEV");
#endif
#if DEBUG
System.Console.WriteLine("DEBUG is ENABLED!");
#else
System.Console.WriteLine("DEBUG is DISABLED!");
#endif
#if TRACE
System.Console.WriteLine("TRACE is ENABLED!");
#else
System.Console.WriteLine("TRACE is DISABLED!");
#endif
System.Console.ReadKey();
}
}
}
请注意第一个#define <Tier>行是如何被删除的,并且在using语句的正上方引入了一个条件。
只需运行上述代码就会导致此客户错误消息,从而破坏我们的编译。
Error CS1029 #error: 'Cannot compile as the Tier is not specified' Pluralsight C:\Users\dszabo\source\repos\Pluralsight\Pluralsight\Program.cs 15 Active
如果我们将第一行加回去,我们将收到以下警告。
Warning CS1030 #warning: 'Running with hard coded Tier information' Pluralsight C:\Users\dszabo\source\repos\Pluralsight\Pluralsight\Program.cs 17 Active
#线
此指令允许您修改编译器的行号,甚至修改错误和警告的文件名。在某些情况下,会从源代码文件中删除特定行,但您需要编译器根据原始行号生成输出,例如旧版和故障排除。此指令很少使用。
你可以向该指令传递三种类型的参数:default、hidden和filename。当你希望编译器忽略该指令时,你可以指定hidden。
假设我们想修改生成警告时报告的文件名。
using System;
namespace Pluralsight
{
#line 1 "Warning line.cs"
class Program
{
static void Main(string[] args)
{
#warning Warning from different filename
System.Console.ReadKey();
}
}
}
无论您实际如何命名文件,执行此操作都会产生以下输出。
<code class="language
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~