Skip to content

Diagnostics in C# 9 & .NET 5 Part 1

When things go wrong, it's critical to have knowledge on hand to help diagnose the problem. An Integrated Development Environment (IDE) or debugger can help a lot with this, but it's usually only available while the programme is being developed.

Image copyrighted to pvs-studio.com



After an application is released, it must collect and record diagnostic data. information. To satisfy this need,.NET includes a set of diagnostic logging tools. Monitoring application behaviour, detecting runtime issues, and integrating data If debugging tools are available, use them. Because they rely on features, several diagnostic tools and APIs are only available on Windows.

Windows is a computer operating system. In order to avoid platform-specific APIs, Microsoft has packaged them as distinct NuGet packages to avoid cluttering the.NET BCL. packages that you can refer to if you want to. There are over a dozen Windows-specific programmes. With the Microsoft. Windows package, you can reference all of them at once.

"Master" package of compatibility. In this article, the types are mostly defined in the System. Diagnostics namespace.

Conditional Compilation

With preprocessor directives in C#, you may build any part of code conditionally. Preprocessor directives are special instructions to the compiler that begin with the # symbol (and must be on their own line, unlike other C# constructs). They should run before the main compilation (but in fact, they are processed by the compiler during the lexical parsing step). #if, #else, #endif, and #elif are conditional compilation preprocessor directives.

The #if directive tells the compiler to skip a piece of code unless a certain symbol is declared. You can define a symbol in source code by using the #define directive (which applies to only that file), or in the .csproj file by using the <DefineConstants> element (which applies to the whole assembly):


The programme would compile with the Console if we omitted the first line. The WriteLine command has been totally removed from the executable, as if it had been commented out.
The #else statement is similar to the else statement in C#, and #elif is the same as #else + #if. The operators ||, &&, and! execute or, and, and not operations, respectively: 

#if TESTMODE &&!PLAYMODE      // if TESTMODE but not PLAYMODE 
...

Keep in mind that you're not creating a standard C# expression, and the symbols you're working with have no link to variables, static or otherwise.
By modifying the .csproj file, you may specify symbols that apply to all files in an assembly (or in Visual Studio, by going to the Build tab in the Project Properties window).
TESTMODE and PLAYMODE are two constants defined as follows:

         <PropertyGroup> 
                 <DefineConstants>
                       TESTMODE;PLAYMODE
                 </DefineConstants> 
         </PropertyGroup>

If you've defined a symbol at the assembly level and subsequently wish to "undefine" it for a specific file, use the #undef directive.


Conditional Compilation Versus Static Variable Flags


You could instead implement the preceding example with a simple static field:

static internal bool TestMode = true;
 
        static void Main()
       {
                  if (TestMode) Console.WriteLine ("in test mode!");
        }

This has the benefit of allowing configuration during runtime. So, what are the advantages of conditional compilation? The reason for this is that conditional compilation may go areas that variable flags can't, such as:

  • Including a characteristic on a conditional basis
  • Changing a variable's stated type
  • In a using directive, switching between distinct namespaces or type aliases; for example:
You may also use a conditional compilation directive to do substantial refactoring, allowing you to switch between old and new versions quickly and create libraries that can compile against different runtime versions, taking advantage of the latest features when they're available.

Another benefit of conditional compilation is that debugging code can refer to types in assemblies that aren't deployed.

The Conditional Attribute

If the supplied symbol has not been declared, the Conditional attribute tells the compiler to disregard all calls to that class or function.

Consider the following approach for recording status information to show how valuable this is:


Consider that you only want this to run if the LOGGINGMODE symbol is present. The first approach is to encapsulate all "LogStatus" calls in a #if directive:



This produces an excellent outcome, but it is time consuming. The #if directive can also be used inside the LogStatus function. This, on the other hand, becomes an issue if LogStatus is called as follows:

     LogStatus ("Message Headers: " + GetComplexMessageHeaders());

GetComplexMessageHeaders would be invoked every time—possibly causing a performance penalty.

By adding the Conditional attribute (provided in System.Diagnostics) to the LogStatus method, we can combine the functionality of the first approach with the ease of the second:



This tells the compiler that calls to LogStatus should be treated as though they were wrapped in a #if LOGGINGMODE directive. Any calls to LogSta tus, including their argument evaluation expressions, are completely removed in compilation if the symbol is not declared. (As a result, any expressions with side effects will be ignored.) Even if LogStatus and the caller are in different assemblies, this works.

Another advantage of [Conditional] is that the conditionality check is done when the caller, not when the called method, is built. This is advantageous because it allows you to develop a library with methods like Log Status and only have to construct one version of that library.

The Conditional property is only used by the compiler and is disregarded during runtime.


Albahari, J., n.d. C# 9.0 in a nutshell. 1st ed. United States of America: O Reilly, pp.571 - 574.

Leave a Reply

Your email address will not be published.