Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
57
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

Chapter 93: Preprocessor directives

Section 93.1: Conditional Expressions

When the following is compiled, it will return a di erent value depending on which directives are defined.

// Compile with /d:A or /d:B to see the difference string SomeFunction()

{

#if A

return "A"; #elif B

return "B"; #else

return "C"; #endif

}

Conditional expressions are typically used to log additional information for debug builds.

void SomeFunc()

{

try

{

SomeRiskyMethod();

}

catch (ArgumentException ex)

{

#if DEBUG log.Error("SomeFunc", ex); #endif

HandleException(ex);

}

}

Section 93.2: Other Compiler Instructions

Line

#line controls the line number and filename reported by the compiler when outputting warnings and errors.

void Test()

{

#line 42 "Answer"

#line filename "SomeFile.cs"

int life; // compiler warning CS0168 in "SomeFile.cs" at Line 42

#line default

// compiler warnings reset to default

}

Pragma Checksum

#pragma checksum allows the specification of a specific checksum for a generated program database (PDB) for debugging.

#pragma checksum "MyCode.cs" "{00000000-0000-0000-0000-000000000000}" "{0123456789A}"

GoalKicker.com – C# Notes for Professionals

508

Section 93.3: Defining and Undefining Symbols

A compiler symbol is a keyword that is defined at compile-time that can be checked for to conditionally execute specific sections of code.

There are three ways to define a compiler symbol. They can be defined via code:

#define MYSYMBOL

They can be defined in Visual Studio, under Project Properties > Build > Conditional Compilation Symbols:

(Note that DEBUG and TRACE have their own checkboxes and do not need to be specified explicitly.)

Or they can be defined at compile-time using the /define:[name] switch on the C# compiler, csc.exe.

You can also undefined symbols using the #undefine directive.

The most prevalent example of this is the DEBUG symbol, which gets defined by Visual Studio when an application is compiled in Debug mode (versus Release mode).

public void DoBusinessLogic()

{

try

{

AuthenticateUser(); LoadAccount(); ProcessAccount(); FinalizeTransaction();

}

catch (Exception ex)

{

#if DEBUG

System.Diagnostics.Trace.WriteLine("Unhandled exception!"); System.Diagnostics.Trace.WriteLine(ex);

throw;

#else

LoggingFramework.LogError(ex);

DisplayFriendlyErrorMessage();

#endif

}

}

In the example above, when an error occurs in the business logic of the application, if the application is compiled in Debug mode (and the DEBUG symbol is set), the error will be written to the trace log, and the exception will be re-

GoalKicker.com – C# Notes for Professionals

509

thrown for debugging. However, if the application is compiled in Release mode (and no DEBUG symbol is set), a logging framework is used to quietly log the error, and a friendly error message is displayed to the end user.

Section 93.4: Region Blocks

Use #region and #endregion to define a collapsible code region.

#region Event Handlers

public void Button_Click(object s, EventArgs e)

{

// ...

}

public void DropDown_SelectedIndexChanged(object s, EventArgs e)

{

// ...

}

#endregion

These directives are only beneficial when an IDE that supports collapsible regions (such as Visual Studio) is used to edit the code.

Section 93.5: Disabling and Restoring Compiler Warnings

You can disable compiler warnings using #pragma warning disable and restore them using #pragma warning restore:

#pragma warning disable CS0168

// Will not generate the "unused variable" compiler warning since it was disabled var x = 5;

#pragma warning restore CS0168

// Will generate a compiler warning since the warning was just restored var y = 8;

Comma-separated warning numbers are allowed:

#pragma warning disable CS0168, CS0219

The CS prefix is optional, and can even be intermixed (though this is not a best practice):

#pragma warning disable 0168, 0219, CS0414

Section 93.6: Generating Compiler Warnings and Errors

Compiler warnings can be generated using the #warning directive, and errors can likewise be generated using the #error directive.

#if SOME_SYMBOL

#error This is a compiler Error. #elif SOME_OTHER_SYMBOL

#warning This is a compiler Warning.

GoalKicker.com – C# Notes for Professionals

510

#endif

Section 93.7: Custom Preprocessors at project level

It is convenient to set custom conditional preprocessing at project level when some actions need to be skipped lets say for tests.

Go to Solution Explorer -> Click Right Mouse on project you want to set variable to -> Properties -> Build -> In General find field Conditional compilation symbols and enter your conditional variable here

Code example that will skip some code:

public void Init()

{

#if !IGNOREREFRESHDB

// will skip code here db.Initialize(); #endif

}

Section 93.8: Using the Conditional attribute

Adding a Conditional attribute from System.Diagnostics namespace to a method is a clean way to control which methods are called in your builds and which are not.

#define EXAMPLE_A

GoalKicker.com – C# Notes for Professionals

511

using System.Diagnostics; class Program

{

static void Main()

{

ExampleA(); // This method will be called ExampleB(); // This method will not be called

}

[Conditional("EXAMPLE_A")] static void ExampleA() {...}

[Conditional("EXAMPLE_B")] static void ExampleB() {...}

}

GoalKicker.com – C# Notes for Professionals

512