Директивы препроцессора в C#: условная компиляция и управление кодом
Что такое директивы препроцессора
Директивы препроцессора — инструкции компилятору обработать код до компиляции. Все начинаются с #, не заканчиваются точкой с запятой. В C# нет отдельного препроцессора (как в C/C++), директивы обрабатываются компилятором. Основное назначение — условная компиляция.
Список директив
| Директива | Описание |
|---|---|
#define SYMBOL | Определяет символ (символическую константу) |
#undef SYMBOL | Отменяет определение символа |
#if SYMBOL | Начало условного блока (компилируется, если символ определён) |
#elif SYMBOL | Альтернативная ветка #if |
#else | Иная ветка #if |
#endif | Конец условного блока |
#warning "text" | Генерирует предупреждение компилятора |
#error "text" | Генерирует ошибку компиляции |
#line number ["file"] | Изменяет номер строки/имя файла для сообщений об ошибках |
#region name | Сворачиваемая область в IDE (Visual Studio, Rider, VS Code) |
#endregion | Конец области #region |
#pragma warning | Управление предупреждениями (disable/restore) |
#nullable | Управление nullable-контекстом (C# 8+) |
#define и #undef
#define DEBUG
#define TRACE
// #undef DEBUG // отменяет
#if DEBUG
Console.WriteLine("Debug mode");
#endif
Символы #define — только для препроцессора, не создают переменных. Обычно определяются в свойствах проекта (Build → Define constants) или в .csproj:
<DefineConstants>DEBUG;TRACE</DefineConstants>
Условная компиляция (#if, #elif, #else, #endif)
#define DEBUG
#define VC_V10
#if DEBUG && !VC_V10
Console.WriteLine("DEBUG only");
#elif !DEBUG && VC_V10
Console.WriteLine("VC_V10 only");
#elif DEBUG && VC_V10
Console.WriteLine("Both defined");
#else
Console.WriteLine("Neither");
#endif
Операторы в выражениях: ==, !=, &&, ||, скобки для группировки.
#warning и #error
#warning "This code is deprecated, use NewMethod instead"
#error "This configuration is not supported"
#error останавливает компиляцию. Полезно для проверки конфигураций.
#region / #endregion
Только для IDE — позволяет сворачивать блоки кода в редакторе. Не влияет на компиляцию.
#region Public Methods
public void Method1() { }
public void Method2() { }
#endregion
#region Private Helpers
private void Helper() { }
#endregion
#line — управление номером строки
#line 100 "MyGeneratedFile.cs"
int x = 1; // ошибка здесь будет сообщена как строка 100 в MyGeneratedFile.cs
#line default // сброс
Используется генераторами кода.
#pragma warning
#pragma warning disable CS0168 // переменная объявлена, но не используется
int unused = 42;
#pragma warning restore CS0168
#nullable (C# 8.0+)
#nullable enable
string? maybeNull = null;
string notNull = "text";
// maybeNull.Length; // Warning CS8602
#nullable disable
// maybeNull.Length; // No warning
ConditionalAttribute — альтернатива #if для методов
Атрибут [Conditional("SYMBOL")] на методе: вызов метода полностью удаляется компилятором, если символ не определён. Чище, чем #if вокруг вызова.
#define DEBUG
using System.Diagnostics;
public class Logger
{
[Conditional("DEBUG")]
public static void Log(string msg) => Console.WriteLine($"[LOG] {msg}");
}
Logger.Log("Start"); // вызовется только если DEBUG определён
// В Release сборке (без DEBUG) вызова вообще не будет в IL
Лучшие практики
- Определяйте символы в настройках проекта (.csproj), а не в коде
- Используйте
ConditionalAttributeдля логирования/метрик вместо#ifвокруг вызовов - Минимизируйте
#ifв бизнес-логике — усложняет чтение и тестирование #region— для группировки в IDE, не злоупотребляйте#warning— для напоминаний команде;#error— для блокировки недопустимых конфигураций
Язык C
- C# Hello World — создание вашего первого C# приложения
- Понимание ключевых слов и идентификаторов C#: правила, списки и лучшие практики
- Мастерство C# переменных и примитивных типов данных: полное руководство
- Операторы C# — исчерпывающее руководство по операторам в C#
- Освоение побитовых и сдвиговых операторов в C#: полное руководство
- Основы ввода-вывода в C#: Console.WriteLine, ReadLine и форматирование
- Выражения, операторы и блоки в C#: подробное руководство с примерами
- Освоение комментариев в C#: виды, лучшие практики и XML-документация
- Освоение оператора switch в C#: синтаксис, примеры и лучшие практики
- Тернарный оператор в C#: краткое руководство по условным выражениям