如何设置条件编译变量?

时间:2010-10-01 19:55:02

标签: c#

在C / C ++中,您可以在代码中定义宏,如下所示:

#define OLD_WAY  1

虽然我从来没有这样做过,但我认为C#中可以使用同样的东西。更重要的是,在C / C ++中,可以通过执行以下操作来执行某些条件编译逻辑:

#if OLD_WAY == 1
 int i = 0;
#else
 int i = 1;
#endif
好的,所以这一切都很酷。而且,我认为这种逻辑在C#中是可能的。我想知道的是,我如何在项目级别定义常量,这样我就可以输入逻辑,如果我定义常量的一个方法或另一个代码块,我将允许我条件编译一个代码块如果我不这样定义?我假设它已经在项目的属性中的某个地方完成,但是我如何定义它以及在何处定义它?

3 个答案:

答案 0 :(得分:48)

C#编译器csc.exe和C#语言本身不会公开conditional compilation的任何预定义常量。 Visual Studio 仅添加DEBUGTRACE值,可以通过IDE进行配置。 IDE还允许您添加自己的任意符号,但由于这些符号基本上是固定的(不变)值,因此该功能的用途有限。

可以通过手动编辑.csproj项目文件来设置更强大的自定义选项。您可以根据conditions中提供的大量环境和配置信息,在此处将selectively propagate MSBuild条件编译符号设置为C#(请参阅here和{{3} }但原则上,可能没有完整的列表,因为不同的组件任意提供元数据 ad-hoc )。

让我们考虑一个有效的例子。有条件编译有用的一种情况是,如果要编写适应构建期间发现的任何工具的代码。通过这种方式,您可以利用最新的语言功能,同时仍然保留在具有旧工具的计算机上进行编译的能力,这可能会像预期的那样拒绝外来语法和/或关键字。对于 Visual Studio 2017 here的特定情况,我们可以修改.csproj,如下所示:

.csproj文件(摘录):

C# 7.0

您也可以识别每个较旧的C#编译器,在此过程中优雅地降级。检测 .NET Framework 版本(在StackOverflow enter image description here上经常请求)也是如此 [1] [2] [3])以及任何其他环境构建条件。这些留给读者练习,但如果你想从上面复制/粘贴突出显示的行,这里是文本版本。作为屏幕截图的更新,我在这里为条件表达式添加了单引号(即使一切看起来没有它们)

<DefineConstants Condition="'$(VisualStudioVersion)'=='15'">CSHARP7</DefineConstants>
<!-- ... -->
<DefineConstants>DEBUG;TRACE;$(DefineConstants)</DefineConstants>
<!-- ... -->
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants>

无论如何,通过这种方式,您现在可以使用#if… #elif… #else… #endif编写条件C#代码。继续示例案例,下面的代码使用新的元组语法 - 仅在C#7中可用 - 来交换数组元素。顺便提一下,元组版本不仅更简洁和/或更优雅;它还可以生成出色的IL代码:

#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代码编辑器正确识别和评估条件编译,目的是IntelliSenserefactoring,“调暗”非活动代码块等。< / p>

我还提到MSBuild有大量可用信息,其中$(VisualStudioVersion)只是一个例子。不幸的是,很难找出哪些值可用以及它们在构建时可能具有的值。一个技巧是暂时将C++项目放入您的Visual Studio解决方案(如果您还没有)与C#项目一起。如果右键单击此.vcxproj项目属性,然后在C/C++页面上查看(例如)“其他包含目录”,则会在最右侧显示一个下拉列表当您点击进行编辑时:

[4]

您将看到一个带有“宏”按钮的对话框,您可以单击此按钮以根据当前在IDE中选择的平台和配置获取所有可用MSBuild变量及其预期值的列表。不要忽略列表底部的enter image description here字段(前缀为%)。

well-known-item-metadata

您可以根据此屏幕截图中滚动条拇指的大小了解此处有多少内容。 (它们按字母顺序列出,我只是滚动到“P”部分的这一部分,因为它具有最少的个人信息)。然而,重要的是要注意,(可用的)变量及其值在构建过程中随着时间的推移而发展,因此您可能会在此列表中找到.csproj 无法使用的项目在它处理时

[edit:]在构建过程中和整个构建过程中找出可用属性值的另一种方法是将MSBuild“输出详细程度”设置为“详细”,然后重建。

enter image description here

构建完成后,检查 Visual Studio 输出窗口中构建日志的顶部,您将看到可用属性名称的列表以及他们的初始值。

答案 1 :(得分:36)

打开项目属性并查看“构建”页面。有一个名为Conditional compilation symbols的框。

enter image description here

答案 2 :(得分:36)

在C#中你可以#define但你不能像在C ++中一样使用它们。
每个定义可以有2种状态:已定义或未定义

在Build下的项目属性中,您可以设置应定义的定义 您在此处指定的任何内容都将在所有项目文件中定义。

例如,我可以在此字段中定义2个条件编译符号:
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

如果您设置条件编译符号,并且除了可能的文件之外的所有文件中都需要它,那么最后一个。