问题描述
在C / C ++中,您可以在这样的代码中定义宏:
#define OLD_WAY 1
尽管我从未做过,但我认为C#中也有同样的东西。更重要的是,在C / C ++中,可以通过执行以下操作来执行一些条件编译逻辑:
#如果OLD_WAY == 1
int i = 0;
#else
int i = 1;
#endif
好的,所以这一切都很酷。再一次,我假设这种逻辑在C#中是可能的。我想知道的是,我如何在项目级别定义常量,以便可以放入逻辑中,如果我以一种方式定义常量或另一段代码,可以让我有条件地编译一个代码块如果我不这样定义的话?我假设它已在项目属性的某个位置完成,但是我如何以及在哪里定义它?
C#编译器 csc.exe
和C#语言本身不公开
您还可以识别每个较旧的C#编译器,并在此过程中进行适当的降级。检测 .NET Framework 版本(在Overflow
您将看到一个带有宏按钮的对话框,您可以单击该对话框以获取所有可用的MSBuild变量及其预期值的列表。当前在IDE中选择的平台和配置。不要忽略
您可以从此屏幕快照中滚动条的大小中了解多少东西。 (它们是按字母顺序列出的;我只是滚动到 P部分的这一部分,因为它的个人信息很少。)但是,值得注意的是,(可用)变量及其值随时间变化。过程,因此您可能会在此列表中找到 .csproj
在处理之时无法使用的项目。
找出构建过程中以及整个构建过程中可用的属性值的另一种方法是将MSBuild的输出详细程度设置为详细,然后重建。
之后构建完成后,在 Visual Studio 输出窗口中检查构建日志的顶部,您将看到可用属性名称及其初始值的列表。
In C/C++ you can define macros in code like this:
#define OLD_WAY 1
Although I've never done it, I assume that the same thing is available in C#. More to the point, in C/C++ it is possible to then do some conditional compilation logic by doing something like this:
#if OLD_WAY == 1
int i = 0;
#else
int i = 1;
#endif
OK, so this is all cool and all that. And again, I assume that such logic is possible within C#. What I'd like to know is, how do I define constants at the project level, so that I can put in logic that will allow me to conditional compile one block of code if I define the constant one way, or another block of code if I don't define it that way? I'm assuming that it's done somewhere in the project's properties, but how and where do I define it?
The C# compiler csc.exe
and the C# language itself do not expose any predefined constants for conditional compilation. Visual Studio only adds the DEBUG
and TRACE
values, which can be configured through the IDE. The IDE also lets you add your own arbitrary symbols, but since these are essentially fixed (invariant) values, the capability is of limited use.
More powerful custom options can set up by manually editing your .csproj
project file. You can set up conditions here to selectively propagate conditional compilation symbols into C# based on the huge amount of environment and configuration information available in MSBuild (see here and here, but in principle, there can be no complete list, since disparate components arbitrarily contribute metadata ad-hoc).
Let's consider a working example. One case where it's useful to conditionally compile is if you want to write code that adapts to the whatever tools are discovered during the build. This way you can exploit the latest language features while still preserving the ability to compile on machines with older tooling which would, as expected, reject the alien syntax and/or keywords. For the particular case of C# 7.0 in Visual Studio 2017 we can modify the .csproj
as follows:
.csproj file (excerpt):
You could also identify each of the older C# compilers as well, degrading gracefully along the way. The same goes for detecting the .NET Framework version (oft-requested on Stack Overflow [1][2][3][4]) and any other ambient build conditions. Such are left as exercises for the reader, but in case you want to copy/paste the highlighted lines from above, here is the text version. As an update over the screenshot, I added single-quotes to the conditional expression here (even though everything seemed to work without them)
<DefineConstants Condition="'$(VisualStudioVersion)'=='15'">CSHARP7</DefineConstants>
<!-- ... -->
<DefineConstants>DEBUG;TRACE;$(DefineConstants)</DefineConstants>
<!-- ... -->
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants>
Anyway, in this manner you can now write conditional C# code using #if… #elif… #else… #endif
. Continuing the example case, the code below uses new tuple syntax--only available in C# 7--to swap array elements. Incidentally, the tuple version is not only more concise and/or elegant; it also produces excellent CIL code:
#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
Note that the Visual Studio IDE does correctly process your manual .csproj
customizations in every regard. Given the .csproj
I showed earlier, the IDE code editor properly recognizes and evaluates conditional compilation for the purposes of IntelliSense
, refactoring
, "dimming-out" inactive blocks of code, etc.
I also mentioned that MSBuild has a treasure trove of information available, of which $(VisualStudioVersion)
was just one example. Unfortunately, there's no easy to find out which values are available and what values they might have at buildtime. A trick is to temporarily put a C++ project into your Visual Studio solution (if you don't already have one) alongside your C# project. If you right click the project properties for this .vcxproj
and then look at (e.g.) "Additional Include Directories" on the C/C++
page, a dropdown will appear at the far right when you click to edit:
You'll get a dialog box with a "Macros" button which you can click to get a list of all the available MSBuild variables plus their expected values according to platform and configuration that are currently selected in the IDE. Don't overlook the well-known item metadata fields (prefixed with %
) at the bottom of the list.
You can get an idea for how much stuff is here from the size of the scrollbar thumb in this screenshot. (They're listed alphabetically; I just scrolled to this part of the 'P' section, because it had minimal personal information.) It's important to note, however, that both the (available) variables and their values evolve over time during the course of the build, so you may find items in this list that aren't available to your .csproj
at the time it's processed.
Another way to find out what property values are available during and throughout your build process is to set the MSBuild "output verbosity" to "Detailed", and then rebuild.
After the build finishes, examine the top of the build log in the Visual Studio Output Window, and you'll see a list of the available property names along with their initial values.
这篇关于如何设置条件编译变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!