⚙️ Директивы препроцессора в C
Директивы препроцессора в C# начинаются с символа #
и обрабатываются до компиляции. Они позволяют управлять частями кода, которые должны быть включены или исключены при компиляции, влиять на поведение предупреждений, группировать код и т.д.
🔧 Что такое препроцессор?
Препроцессор — это механизм, который анализирует и изменяет код до передачи его компилятору. В отличие от C/C++, в C# препроцессор не является отдельной стадией компиляции, но поддерживает несколько ключевых директив.
📜 Основные директивы
Директива | Назначение |
---|---|
#define |
Определяет символ для условной компиляции |
#undef |
Удаляет символ |
#if , #elif , #else , #endif |
Условная компиляция |
#region , #endregion |
Сворачиваемые блоки в IDE |
#warning , #error |
Добавляют предупреждение или ошибку при компиляции |
#line |
Изменяет номер строки и имя файла для диагностики |
#pragma |
Управляет предупреждениями компилятора |
🧠 #define
и #undef
#define DEBUG
#undef EXPERIMENTAL
````
> Обычно такие символы определяются **в настройках проекта** или через IDE, а не вручную в коде.
---
## 🔀 Условная компиляция (`#if`, `#else`, `#elif`, `#endif`)
```csharp
#define DEBUG
class Program {
static void Main() {
#if DEBUG
Console.WriteLine("Режим отладки");
#else
Console.WriteLine("Релизная сборка");
#endif
}
}
Можно использовать логические операторы:
#if DEBUG && !EXPERIMENTAL
Console.WriteLine("Debug без экспериментальных фич");
#endif
🧭 #region
и #endregion
Просто создают сворачиваемую область кода в IDE.
#region Сетевые функции
void Connect() { }
void Disconnect() { }
#endregion
⚠️ #warning
и #error
#warning Этот код устарел — используйте метод ConnectV2
#error Обязательное поле CONFIG_KEY не определено
Такие директивы часто используют для напоминаний или защиты от неправильной сборки.
🎯 #pragma
📌 #pragma warning
Позволяет управлять предупреждениями компилятора: отключать, включать, временно подавлять.
#pragma warning disable CS0219 // Переменная объявлена, но не используется
int unused = 0;
#pragma warning restore CS0219
CS0219
— код предупреждения компилятора (можно навести курсор в IDE).- Можно отключить все предупреждения:
#pragma warning disable
- И снова включить:
#pragma warning restore
🔍 Где это полезно?
- Для "грязных" участков кода, где ты осознанно игнорируешь правило:
csharp
#pragma warning disable CS0168
try {
// переменная ex не используется, но нужна для отладки
} catch (Exception ex) { }
#pragma warning restore CS0168
- При миграции кода, когда нужно временно подавить множество предупреждений.
📋 Другие директивы
#line
Редко используется, но позволяет "переопределить" номер строки и имя файла:
#line 100 "VirtualFile.cs"
Console.WriteLine("Ошибка в виртуальном файле");
#line default
Часто применяется при генерации кода.
#nullable
Управляет поведением аннотаций nullable в новых версиях C#:
#nullable enable
string? s = null;
#nullable disable
⚙️ Настройка символов в .csproj
Вместо #define
в коде лучше определить символы в файле проекта:
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DefineConstants>DEBUG;TRACE;EXPERIMENTAL</DefineConstants>
</PropertyGroup>
💡 Примеры реального применения
Сценарий | Решение |
---|---|
Разные блоки кода для Debug и Release | #if DEBUG |
Поддержка нескольких платформ | #if WINDOWS , #if LINUX , #if ANDROID |
Подавление предупреждений для миграции | #pragma warning disable |
Временное отключение экспериментов | #if EXPERIMENTAL |
Визуальное оформление больших кусков кода | #region , #endregion |
Вставка заглушек и ограничений в код | #error , #warning |
🚫 Что директивы не делают?
- Не влияют на поведение во время выполнения
- Не заменяют конфигурацию через переменные среды или appsettings.json
- Не работают как
#include
в C++
🧪 Пример: включение логики только при отладке
public class Logger {
[Conditional("DEBUG")]
public static void Log(string message) {
Console.WriteLine(message);
}
}
System.Diagnostics.ConditionalAttribute
работает аналогично#if DEBUG
, но для методов. Метод просто не попадёт в компиляцию, если DEBUG не определён.
📌 Заключение
Директивы препроцессора полезны для:
- Управления конфигурациями (Debug/Release)
- Поддержки кроссплатформенности
- Временного управления кодом и предупреждениями
Но они должны использоваться умеренно, чтобы не сделать проект слишком запутанным.