2010-10-01 111 views
23

在C/C++,你可以在代码中定义的宏是这样的:如何设置条件编译变量?

#define OLD_WAY 1 

虽然我从来没有做过,我认为同样的事情在C#中可用。更重要的是,在C/C++,可以再由做这样的事情做一些条件编译逻辑:

#if OLD_WAY == 1 
int i = 0; 
#else 
int i = 1; 
#endif 

OK,所以这是所有的凉爽和所有。再次,我假设这种逻辑在C#中是可能的。我想知道的是,如何在项目级别定义常量,以便我可以放入逻辑,以便我可以有条件地编译一段代码,如果我定义一个常量或另一个代码块如果我不这样定义它?我假设它是在项目的属性中完成的,但我如何以及在哪里定义它?

回答

19

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

更强大的自定义选项可以通过手动编辑您的.csproj项目文件来设置。根据MSBuild(见herehere)提供的大量环境和配置信息,您可以在这里将conditions设置为selectively propagateselectively propagate条件编译为C#,但原则上可能没有完整列表,因为不同组件会任意贡献元数据特设)。

让我们考虑一个工作示例。有条件编译有用的一种情况是,如果您想编写适合构建过程中发现的任何工具的代码。通过这种方式,您可以利用最新的语言功能,同时仍能够保留在具有较旧工具的机器上进行编译的能力,而这正如预期的那样会拒绝外来语法和/或关键字。对于C# 7.0vs2017特定的情况下,我们可以通过修改.csproj如下:

.csproj的文件(节选):

enter image description here

您还可以识别每个上了年纪的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中可用 - 交换数组元素。顺便提一句,元组版本不仅更简洁和/或优雅,它也产生优异的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,“调出”的代码不激活块等

我也提到了MSBuild有一个宝库的信息可用,其中$(VisualStudioVersion)只是一个例子。不幸的是,不容易找出哪些值是可用的,以及它们在构建时可能具有的值。一个诀窍就是临时把C++项目放到你的C#项目旁边的Visual Studio解决方案中(如果你还没有的话)。如果您右键点击项目属性对于此.vcxproj,然后查看(例如,)“附加包含目录”的C/C++页面上,一个下拉菜单会出现在最右边,当您单击编辑:

enter image description here

你会得到一个对话框,以“宏”按钮,就可以单击以获取所有可用变量的列表以及根据当前在IDE中选择的平台和配置的预期值。请不要忽略列表底部的well-known-item-metadata字段(前缀为%)。

enter image description here

你可以得到很多东西是如何在这里从这张截图的滚动条拇指大小的想法。 (它们按字母顺序排列,我只是滚动到“P”部分的这部分,因为它的个人信息很少)。然而,需要注意的是,在构建过程中,(可用)变量及其值随着时间的推移而变化,因此您可能会发现此列表中的项目在处理时不可用于您的.csproj

+0

Awsome!这个答案需要更多的投票!特别是对于C++提示:-) – Matt 2017-05-12 13:16:16

27

打开您的项目属性并查看Build页面。有一个名为Conditional compilation symbols的框。

enter image description here

+1

@toddmo你在说什么?它在VS2015中的位置与15年前的每个版本都一样。 – 2016-11-05 16:25:51

31

在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 

如果设置了这最后一个,你会怎么做有条件的编译符号,并且您希望除了一个文件以外的所有文件。

相关问题