Skip to Content
Course content

215: Preprocessor Directives: #if, #region, #pragma

Click on the "Edit" button in the top corner of the screen to edit your slide content.

How do I run different code during debugging versus production?

You've probably noticed that during development, you want tons of detailed logs, but in a production environment, those same logs would kill your performance or leak sensitive data. This is where #if comes in. Unlike a standard if statement, which is evaluated while the program is running, a preprocessor directive is evaluated by the compiler before the code is even turned into IL.

If the condition isn't met, the compiler literally acts as if that code doesn't exist. It won't even be in the final DLL.

public void ProcessPayment(Order order)
{
    #if DEBUG
        Console.WriteLine($"[DEBUG] Processing payment for Order {order.Id}. Internal state: {order.InternalDebugInfo}");
    #endif

    PaymentGateway.Charge(order.Amount);
}

In the example above, the Console.WriteLine only exists in your Debug build. When you switch to Release mode, that line is stripped out entirely. I usually use this for heavy telemetry or "sanity check" assertions that would be too slow for a real user to encounter.

Is #region actually useful or just a way to hide messy code?

To be honest, this is a debated topic among engineers. Some people think #region is a "code smell" because if you need to collapse your code to make it readable, your class is probably too long. But in the real world, we often deal with massive legacy files or classes that have a lot of boilerplate properties.

I use regions to group related private helper methods or to separate the "public API" of a class from its internal implementation details. It's purely for the human reading the code; the compiler ignores it completely.

public class DatabaseManager
{
    #region Connection Logic
    private void OpenConnection() { /* ... */ }
    private void CloseConnection() { /* ... */ }
    private void ValidateCredentials() { /* ... */ }
    #endregion

    #region Data Queries
    public User GetUser(int id) { /* ... */ }
    public List<Order> GetOrders() { /* ... */ }
    #endregion
}

Just a word of advice: don't overdo it. If you have ten nested regions, you're not organizing your code—you're just hiding the chaos.

How do I stop the compiler from nagging me about a specific warning?

Sometimes you know exactly why you're doing something, but the compiler still throws a warning. Maybe you're implementing an interface where one method is intentionally left blank, or you're using a deprecated API because the new one isn't supported on an older OS you still have to target.

You can use #pragma warning to tell the compiler to shut up for a moment. The key is to disable the warning, do the "risky" thing, and then immediately re-enable it so you don't accidentally ignore that warning everywhere else in your project.

public void LegacyCleanup()
{
    #pragma warning disable CS0168 // Variable declared but never used
    string oldSystemToken = "ABC-123"; 
    // I need this here for a specific reflection-based tool, 
    // even though I don't use it in the code logic.
    #pragma warning restore CS0168
}

I really recommend adding a comment (like I did above) explaining why you're disabling the warning. Six months from now, you won't remember why you silenced it, and your future self will thank you for the note.




📋 Practical Task

Exercise: Building a Platform-Aware Logger

You are building a logging utility that needs to behave differently based on the build configuration and a custom symbol. Complete the following requirements:

  • Create a class named DiagnosticLogger.
  • Add a method LogMessage(string message).
  • Inside LogMessage, use #if DEBUG to print the message to the console with a "DEBUG: " prefix.
  • Use #else to print the message with an "INFO: " prefix for non-debug builds.
  • Create a private method called InternalTrace() that is intentionally empty. Use #pragma warning disable CS0168 and #pragma warning restore CS0168 inside this method to silence a "variable declared but never used" warning for a local variable you create inside it.
  • Wrap all your private helper methods (including InternalTrace) inside a #region titled "Internal Helpers".
Rating
0 0

There are no comments for now.

to be the first to leave a comment.