I think this is a simple question so I assume I'm missing something obvious. I don't really ever use preprocessor directives but I was looking at someone's code which did and thought it was something I should be familiar with.
So I looked at the msdn example here it has the code:
#define DEBUG
// ...
#if DEBUG
Console.WriteLine("Debug version");
#endif
My two questions are:
in the example above why do they define DEBUG? I was under the impression that was set if you compile in debug v. release mode?
looking at the other example which has #define MYTEST and then writes to the console dependent on if it 'defined', but how does this differ from just using a variable? What am I missing here?
I would actually recommend using the Conditional Attribute instead of inline #if statements.
[Conditional("DEBUG")]
private void DeleteTempProcessFiles()
{
}
Not only is this cleaner and easier to read since you don't end up having #if, #else within your code. This style is less prone to errors either during normal code edits and well as logic flow errors.
Generally, the optional/conditional compilation symbols will be provided by the build script. It is pretty rare to see #define, except for very debug code (if you see what I mean).
Re using a variable; I often use such conditions to handle code that must run on different runtimes (mono, cf, silverlight, etc). A variable cannot suffice because the code cannot be compiled against the wrong platform (missing types/methods etc).
In the example presented I would probably just have used Debug.WriteLine; since this is decorated with [Conditional("DEBUG")], all calls to it are automatically removed if DEBUG is not defined at build.
in the example above why do they define DEBUG? I was under the impression that was set if you compile in debug v. release mode?
Probably because it is example code. It is meant to demonstrate how #ifdef and friends work. I wouldn't expect you to define symbols like that in source files, unless it is for a quick test.
looking at the other example which has "#define MYTEST" and then writes to the console dependent on if it 'defined', but how does this differ from just using a variable? What am I missing here?
If MYTEST is not defined at compile time, the compiler will not actually emit the code between the #if and #endif blocks. Therefore the resultant IL will be smaller.
Also, note that these are not preprocessor directives in C#.
If you use variable all your code is compiled, when you use preprocessor directives only part of code included in executable/dll.
I would like to give one example where I have used preprocessor directive in my project.
My program creates lot of intermediate files on disk. I used #DEBUG directive to delete those files only if my project is in release mode, otherwise I keep those file so that we can view those intermediate files and determine whats happening inside.
When my app is working on production server, I build project in release mode so those files are deleted after processing is complete.
#if (DEBUG==false)
deleteTempFiles()
#endif
I have some code which needs a different handling when using the Mono environment instead of the CLR - thus I have a Mono directive in some of my modules. I think this is a better example than debug
I've used it for a lot of things. Debug messages that I only want in debug builds; clean up temp files; include diagnostic functions or actions.
Related
I have a C# project that has some solution wide defines in Conditional compilation symbols, see here
I now want to unit test that code and I need to undefine some of those variables.
For Unit testing I have a xUnit project that references the solution with the defines.
Is it possible in VS2019 to disable those defines?
Edit
In my specific case I have a Unity project added to my solution. Unity has Unity-specific code that cannot be executed in unit tests such like xUnit.
In order to cope with that, I wrap Unity-specific code (like Logging via Debug.Log) into a define UNITY_2020 that is automatically defined by the Unity project-file.
Now on the unit test side I want to undefine said preprocessor UNITY_2020. As I have the source code (no DLL or nuget), I hope that there is a way to compile and run my unit tests without having troubles with Unity-specific code.
So far, putting #undef UNTIY_2020 at the top of my test files does not help.
"Disable" is not quite the correct terminology, but that's ok. It is possible to undefine symbols by using the #undef preprocessor directive. You can read about it on C# preprocessor directives.
For example, you can place an #undef at the top of a file (actually anywhere really):
#undef CSHARP_7_OR_LATER
...
#if !CSHARP7_OR_LATER
// some code that can now be tested...
#endif
Also, preprocessor symbols apply to files (technically, to a compilation unit), and just happen to be commonly defined (or not) in your .csproj. At compile-time, these and passed to the compiler. So... they are not solution-wide unless you define them for all of the projects.
If the referenced projects are referenced via assembly or NuGet references, you will not be able to affect the compiled code, because, well, it's already compiled.
If, instead, you are referencing the projects directly, or the code directly (e.g. with add or add link) you can either modify the files as I stated, or you could create a new build configuration for each project and the solution, and then define (or not) the preprocessor symbols there.
I'm trying to understand how #if statement works on C# and how it is used.
After reading some documentation, I have got to the conclusion that it is used to compile the code in it if the "symbol" in the condition is defined.
#if DEBUG
Console.WriteLine("Debug version");
#endif
The problem here is that I don't know what they mean by "symbol" (in this case, DEBUG), and I'm struggling to find an answer due to the wide meaning of this word.
What are these "symbols" and what is the purpose of these "preprocessor directives"?
As folks already said, it is a pre-processor directive. Code inside the #if DEBUG ... #endif will get conditionally compiled, depending on whether the symbol DEBUG is defined.
In this case, DEBUG is simply a symbolic name introduced specifically for the pre-processor so that it can distinguish blocks of code that should or should not be compiled.
You can define a new pre-processor symbol in the project settings:
Here, we have a total of four symbols defined:
DEBUG
TRACE
ANOTHER_SYMBOL
YET_ANOTHER_SYMBOL
DEBUG and TRACE are kind of special because they are so widespread. This is why they have dedicated checkboxes. The term "constant" here is used interchangeably with the term "symbol". However, I hear "symbol" more frequently in this particular context.
Another way to define a symbol is through code. You can add #define directives at the very beginning of your .cs source files:
#define YET_ANOTHER_SYMBOL
Those are PreProcessor Directives. In your case, it will check if the DEBUG symbol is defined saying #define DEBUG then the piece of code Console.WriteLine will gets executed
#if DEBUG
Console.WriteLine("Debug version");
#endif
As you already assumed the DEBUG-symbol is used by the compiler in order to either translate the code or not. So in a release-build - where DEBUG doesn´t exist - the code is not compiled into IL.
A symbol here means a variable introduced to the compiler. Those are defined in VS Project Properties-->Build-->conditional complation symbols. However there exists a set of pre-defined symbols - such as DEBUG.
In addition to the predefined, you can also define your own conditional compilation symbol either at the file-level or the project level:
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.conditionalattribute?redirectedfrom=MSDN&view=netframework-4.7.2
e.g, type this at the start of the file to define "CONDITION1"
#define CONDITION1
or define them under the project properties-->build-->Conditional compilation symbols.
Here you can also see the "debug" and "trace" constants predefined (if checked for your config).
"Symbols" in this context means identifiers that are called "conditional compilation symbols" and are only useful for the #if directive.
You can set them:
In VS from Project properties->build->conditional compilation symbols (as #HimBromBreere wrote) note that there are checkboxes for the commonly used DEBUG and TRACE symbols
From the compiler command line with the -define option
In the code with the #define directive
I’m looking at some C# code, and have come across the following statement:
#if DEBUG
// Do something here
#else
// Do something else
#endif
I assumed that DEBUG would be a defined somewhere as follows:
#define DEBUG
But I’m unable to find such a definition, although the code seems to behave as though it were set. Is DEBUG a special case, and if so, how is it set / unset?
On the project, go to Properties -> Build. Under general, you have an option there for defining both DEBUG and TRACE.
It is set with the #define directive or in the compiler settings. It is common for DEBUG to be defined in debug releases, so you could conditionally compile some code like in your example.
You can read more about it on MSDN.
If you look in the project properties you will find a debug option DEBUG
Then you can do in C#:
[Conditional("Debug")]
public void DebugThis()
{
}
You can also define the DEBUG and TRACE conditional compilation constants under the project Properties' Build tab. For this instance, Define DEBUG constant checkbox is probably checked for your project.
More details # MSDN.
In C++ we can use #ifdef to eliminate some debug statements when we release. C# is different from C++ in preprocessor. Can I still get the same result useing C# #if. We want to eliminate ALL debug statements by change one place and we have several different types of debug statements. Can have one file which contains ALL our #ifdef flags to turn on or turn off those debug statements? thanks
You can wrap code in:
#if DEBUG
// debug only code
#endif
However, I don't recommend this. It's often a better alternative to just make a method and flag it with the [Conditional("DEBUG")] attribute. See Conditional on MSDN for more details. This allows you to make debug only methods:
[Conditional("DEBUG")]
public void DebugPrint(string output) { // ...
}
Then, you can call this normally:
DebugPrint("Some message"); // This will be completely eliminated in release mode
Use something like:
#if DEBUG
System.Console.WriteLine("This is debug line");
#endif
The according the MSDN docs
The scope of a symbol created by using #define is the file in which it was defined.
So you can't have a file that defines several other defines that are used throughout your program. The easiest way to do this would be to have different configurations on your project file and specifying the list of defines for each configuration on the command line to the compiler.
Update:
You can set your project defines in Visual Studio by right-clicking on your project and selecting Properties. Then select the Build tab. Under general you can specify the defines to be sent to the compiler under "Conditional compilation symbols". You can define different project settings using the Configuration Manager (Build->Configuration Manager)
Update 2:
When the "Conditional compilation symbols" are specified, Visual Studio emits a /define on the command line for the compiler (csc.exe for C#), you can see this by examining the output window when building your project. From the MSDN docs for csc.exe
The /define option has the same effect
as using a #define preprocessor
directive except that the compiler
option is in effect for all files in
the project. A symbol remains defined
in a source file until an #undef
directive in the source file removes
the definition. When you use the
/define option, an #undef directive in
one file has no effect on other source
code files in the project.
You can use symbols created by this
option with #if, #else, #elif, and
#endif to compile source files conditionally.
I have a large application that I can build through the command line. I want to specify a flag that enables me to compile it into either one of two modes, Actual or Simulated.
So the main issue is, how can I use the preprocessor to programmatically add a reference?
For example:
#if SIMULATED
include SimulatedFiles;
myFactory = new SimulatedFiles.simFactory();
#else
myFactory = new realFactory();
#endif
I don't want any simulated files to compiled into my "actual" application. Since there is no "include" directive in C#, I am stuck on how to accomplish this.
You cannot do this via a C# preprocessor statement because the language doesn't support the notion of references via preprocessor macros.
What you can do is use a msbuild file and alter the set of references added based on msbuild parameters.
nant/msbuild and dependency injection tool with xml configuration?
In C#, there is no real preprocessor, as you can read on the C# Preprocessor's documentation.
From the documentation (emphasis mine):
While the compiler does not have a separate preprocessor, the directives described in this section are processed as if there was one; these directives are used to aid in conditional compilation. Unlike C and C++ directives, you cannot use these directives to create macros.
Are the include files your own source code, or third-party assembly dlls?
If they are your own sources, then you can easily use conditional compilation to remove the "simulated" code from your release build, exactly as you have done in your example (just replace 'include' with 'using'). This is common practice with debugging classes for example.
If you don't "control" the source code for the includes, then you can still add a project reference, but if you conditionally compile all the code that uses the assembly, your applicaton won't ever attempt to access the assembly, so it doesn't need to be be present when the code is running.
(Another possiblity that seems less useful for you is to write a "dummy" version of the referenced assembly that you ship in place of the "real" one, or a proxy that calls the real third-party dll in simulated builds only. If it supplies the public classes and methods that you call, you can ship the dummy instead of the simulated assembly to your customers)