在C / C ++中,您可以在代码中定义宏,如下所示:
#define OLD_WAY 1
虽然我从来没有这样做过,但我认为C#中可以使用同样的东西。更重要的是,在C / C ++中,可以通过执行以下操作来执行某些条件编译逻辑:
#if OLD_WAY == 1
int i = 0;
#else
int i = 1;
#endif
好的,所以这一切都很酷。而且,我认为这种逻辑在C#中是可能的。我想知道的是,我如何在项目级别定义常量,这样我就可以输入逻辑,如果我定义常量的一个方法或另一个代码块,我将允许我条件编译一个代码块如果我不这样定义?我假设它已经在项目的属性中的某个地方完成,但是我如何定义它以及在何处定义它?
答案 0 :(得分:48)
C#编译器csc.exe
和C#语言本身不会公开conditional compilation的任何预定义常量。 Visual Studio 仅添加DEBUG
和TRACE
值,可以通过IDE进行配置。 IDE还允许您添加自己的任意符号,但由于这些符号基本上是固定的(不变)值,因此该功能的用途有限。
可以通过手动编辑.csproj
项目文件来设置更强大的自定义选项。您可以根据conditions中提供的大量环境和配置信息,在此处将selectively propagate MSBuild条件编译符号设置为C#(请参阅here和{{3} }但原则上,可能没有完整的列表,因为不同的组件任意提供元数据 ad-hoc )。
让我们考虑一个有效的例子。有条件编译有用的一种情况是,如果要编写适应构建期间发现的任何工具的代码。通过这种方式,您可以利用最新的语言功能,同时仍然保留在具有旧工具的计算机上进行编译的能力,这可能会像预期的那样拒绝外来语法和/或关键字。对于 Visual Studio 2017 中here的特定情况,我们可以修改.csproj
,如下所示:
.csproj文件(摘录):
您也可以识别每个较旧的C#编译器,在此过程中优雅地降级。检测 .NET Framework 版本(在StackOverflow 上经常请求)也是如此 [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代码编辑器正确识别和评估条件编译,目的是IntelliSense
,refactoring
,“调暗”非活动代码块等。< / p>
我还提到MSBuild
有大量可用信息,其中$(VisualStudioVersion)
只是一个例子。不幸的是,很难找出哪些值可用以及它们在构建时可能具有的值。一个技巧是暂时将C++
项目放入您的Visual Studio
解决方案(如果您还没有)与C#项目一起。如果右键单击此.vcxproj
的项目属性,然后在C/C++
页面上查看(例如)“其他包含目录”,则会在最右侧显示一个下拉列表当您点击进行编辑时:
您将看到一个带有“宏”按钮的对话框,您可以单击此按钮以根据当前在IDE中选择的平台和配置获取所有可用MSBuild
变量及其预期值的列表。不要忽略列表底部的字段(前缀为%
)。
您可以根据此屏幕截图中滚动条拇指的大小了解此处有多少内容。 (它们按字母顺序列出,我只是滚动到“P”部分的这一部分,因为它具有最少的个人信息)。然而,重要的是要注意,(可用的)变量及其值在构建过程中随着时间的推移而发展,因此您可能会在此列表中找到.csproj
无法使用的项目在它处理时。
[edit:]在构建过程中和整个构建过程中找出可用属性值的另一种方法是将MSBuild“输出详细程度”设置为“详细”,然后重建。
构建完成后,检查 Visual Studio 输出窗口中构建日志的顶部,您将看到可用属性名称的列表以及他们的初始值。
答案 1 :(得分:36)
答案 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
如果您设置条件编译符号,并且除了可能的文件之外的所有文件中都需要它,那么最后一个。