如何设置条件编译变量?
Posted
技术标签:
【中文标题】如何设置条件编译变量?【英文标题】:How do I set a conditional compile variable? 【发布时间】:2011-04-20 01:06:57 【问题描述】:在 C/C++ 中,您可以像这样在代码中定义宏:
#define OLD_WAY 1
虽然我从未这样做过,但我认为 C# 中也有同样的功能。更重要的是,在 C/C++ 中,可以通过执行以下操作来执行一些条件编译逻辑:
#if OLD_WAY == 1
int i = 0;
#else
int i = 1;
#endif
好的,所以这一切都很酷。再一次,我假设这种逻辑在 C# 中是可能的。我想知道的是,如何在项目级别定义常量,以便我可以输入逻辑,如果我以一种方式定义常量或另一块代码,则允许我有条件地编译一个代码块如果我不这样定义它?我假设它是在项目属性的某个地方完成的,但我如何以及在哪里定义它?
【问题讨论】:
【参考方案1】:打开您的项目属性并查看构建页面。有一个框叫条件编译符号:
【讨论】:
语法是什么?我的项目只考虑符号集,如果它等于字符串'true' 哦,msbuild 文件中的Condition
与此处设置的符号无关。尽管如此,语法问题仍然适用。是逗号分隔、空格分隔、分号分隔吗?
你可以用逗号分隔条件【参考方案2】:
在 C# 中,您可以使用 #define
,但不能像在 C++ 中那样对它们使用值。每个定义可以有两种状态:已定义或未定义
在 Build 下的项目属性中,您可以设置应定义的定义。您在此处指定的任何内容都将在您的所有项目文件中定义。
所以例如我可以在这个字段中定义两个条件编译符号为:
MY_DEFINE1, MY_DEFINE2
然后在我的代码中我可以做这样的事情:
#if MY_DEFINE1
// Do something conditionally
#endif
#if MY_DEFINE2
// Do something else conditionally
#endif
或者,您可以对每个文件进行定义,但与 C++ 不同,它们必须位于文件的顶部。
您可以在文件顶部使用:
#define MY_DEFINE2
或者您可以在文件顶部使用:
#undef MY_DEFINE2
如果你设置了一个条件编译符号并且你希望它出现在所有文件中,除了一个,你会做最后一个。
【讨论】:
可以设置所有文件吗?【参考方案3】:C# 编译器csc.exe
和C# 语言本身不公开任何conditional compilation 的预定义常量。 Visual Studio 只添加了DEBUG
和TRACE
值,可以通过IDE 进行配置。 IDE 还允许您添加自己的任意符号,但由于这些符号本质上是固定(不变)值,因此该功能的用途有限。
可以通过手动编辑您的.csproj
项目文件来设置更强大的自定义选项。您可以根据MSBuild中提供的大量环境和配置信息将conditions这里设置为selectively propagate条件编译符号到C#中(参见here和here,但原则上可以没有完整列表,因为不同的组件随意贡献元数据ad-hoc)。
让我们考虑一个工作示例。有条件编译有用的一种情况是,如果您想编写适应构建期间发现的任何工具的代码。通过这种方式,您可以利用最新的语言功能,同时仍然保留在使用旧工具的机器上编译的能力,正如预期的那样,这些工具会拒绝外来语法和/或关键字。对于 Visual Studio 2017 中 C# 7.0 的特殊情况,我们可以修改 .csproj
如下:
.csproj 文件(摘录):
您还可以识别每个较旧的 C# 编译器,并在此过程中优雅地降级。检测 .NET Framework 版本也是如此(在 *** 上经常请求 [1] [2] [3] [4]) 和任何其他环境构建条件。这些留给读者练习,但如果您想从上面复制/粘贴突出显示的行,这里是文本版本。作为对屏幕截图的更新,我在此处为条件表达式添加了单引号(即使没有它们似乎一切正常)
<DefineConstants Condition="'$(VisualStudioVersion)'=='15'">CSHARP7</DefineConstants>
<!-- ... -->
<DefineConstants>DEBUG;TRACE;$(DefineConstants)</DefineConstants>
<!-- ... -->
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants>
无论如何,通过这种方式,您现在可以使用#if… #elif… #else… #endif
编写条件 C# 代码。继续示例案例,下面的代码使用新的元组语法(仅在 C# 7 中可用)来交换数组元素。顺便说一句,元组版本不仅更简洁和/或优雅;它还可以生成出色的 CIL 代码:
#if CSHARP7
(rg[i], rg[j]) = (rg[j], rg[i]); // Swap elements: tuple syntax
#else
var t = rg[i]; // Swap elements: clunky
rg[i] = rg[j];
rg[j] = t;
#endif
请注意,Visual Studio IDE确实在各个方面都能正确处理您的手动 .csproj
自定义设置。鉴于我之前展示的.csproj
,IDE 代码编辑器可以正确识别和评估条件编译,以用于IntelliSense
、refactoring
、“调光”非活动代码块等。
我还提到MSBuild 有一个可用的信息宝库,其中$(VisualStudioVersion)
只是一个例子。不幸的是,要找出哪些值可用以及它们在构建时可能具有哪些值并不容易。一个技巧是将 C++ 项目与 C# 项目一起临时放入您的 Visual Studio 解决方案(如果您还没有)。如果您右键单击此.vcxproj
的项目属性,然后在C/C++
页面上查看(例如)“其他包含目录”,当您单击时,最右侧会出现一个下拉菜单编辑:
您将看到一个带有“宏”按钮的对话框,您可以单击该按钮来获取所有可用 MSBuild 变量的列表以及根据当前在 IDE 中选择的平台和配置的预期值。不要忽略列表底部的well-known item metadata 字段(以%
为前缀)。
您可以通过此屏幕截图中滚动条拇指的大小来了解这里有多少内容。 (它们按字母顺序列出;我只是滚动到“P”部分的这一部分,因为它包含的个人信息很少。)然而,重要的是要注意,(可用的)变量及其值在构建过程,因此您可能会在此列表中找到您的.csproj
不可用的项目在处理时。
在构建过程中和整个构建过程中找出哪些属性值可用的另一种方法是将 MSBuild“输出详细程度”设置为“详细”,然后重新构建。
构建完成后,在 Visual Studio 输出窗口中检查构建日志的顶部,您将看到可用属性名称的列表以及它们的初始值。
【讨论】:
以上是关于如何设置条件编译变量?的主要内容,如果未能解决你的问题,请参考以下文章
如何优化Oracle在where条件中用了自定义函数的SQL语句