Скрытые возможности C#, о которых вы могли не знать: полезные трюки и синтаксический сахар
1. Null-conditional и null-coalescing операторы — ваш ежедневный хлеб
Ваш пример можно переписать в одну строку:
public string GetUserName(User user) => user?.Name ?? "Guest";
Оператор ?. (null-conditional) безопасно обращается к свойству Name, если user не null. Если user или Name null, результат будет null. Затем ?? (null-coalescing) подставляет значение "Guest" в случае null.
2. Оператор switch с pattern matching (C# 7+)
Забудьте про громоздкие if-else. Современный switch умеет проверять типы и условия:
public string Describe(object obj) => obj switch
{
int i when i > 0 => $"Положительное число: {i}",
int i when i < 0 => $"Отрицательное число: {i}",
string s => $"Строка длиной {s.Length}",
null => "Это null",
_ => "Что-то другое"
};
Ключевое слово _ — это discard (отбрасывание), оно работает как default-case.
3. yield return — ленивая генерация последовательностей
Вместо создания временного списка используйте yield:
public IEnumerable<int> GetEvenNumbers(int limit)
{
for (int i = 0; i <= limit; i += 2)
{
yield return i; // элемент вычисляется только когда его запрашивают
}
}
Это особенно полезно при работе с большими данными — элементы генерируются "на лету", экономя память.
4. using static — импорт статических методов
Добавьте using static System.Math; в начале файла и пишите Abs(-5) вместо Math.Abs(-5). Удобно для математических операций или консольного ввода-вывода.
5. Инициализаторы объектов и коллекций
var person = new Person
{
Name = "Alice",
Age = 30,
Hobbies = { "Reading", "Gaming" } // добавление в коллекцию
};
Обратите внимание: для коллекций не нужно явно вызывать Add.
6. nameof — безопасное получение имени переменной
public void SetProperty(string value)
{
if (value == null)
throw new ArgumentNullException(nameof(value)); // строка "value"
}
При рефакторинге имя обновится автоматически, в отличие от строковых литералов.
7. Локальные функции
Объявляйте функции внутри методов для инкапсуляции логики:
public int Calculate(int x, int y)
{
int Add() => x + y; // замыкание на параметры метода
return Add() * 2;
}
8. Tuple-синтаксис (C# 7+)
// Возврат нескольких значений без out-параметров
public (int sum, int product) Calculate(int a, int b) => (a + b, a * b);
// Использование
var result = Calculate(3, 4);
Console.WriteLine($"Сумма: {result.sum}, Произведение: {result.product}");
9. Индексы и диапазоны (C# 8+)
int[] numbers = { 0, 1, 2, 3, 4, 5 };
Console.WriteLine(numbers[^1]); // 5 (последний элемент)
var slice = numbers[1..^1]; // { 1, 2, 3, 4 }
Оператор ^ отсчитывает с конца, .. создает диапазон.
10. Асинхронные стримы (C# 8+)
public async IAsyncEnumerable<int> GetNumbersAsync()
{
for (int i = 0; i < 10; i++)
{
await Task.Delay(100);
yield return i; // асинхронная генерация
}
}
// Потребление:
await foreach (var num in GetNumbersAsync())
{
Console.WriteLine(num);
}
Помните: скрытые фичи — это не магия, а инструменты. Используйте их, когда они делают код чище, а не ради "красоты".
<<Несколько дополнительных трюков, которые стоит знать
Коллега выше отлично описал основные фичи. Добавлю пару менее очевидных, но очень полезных моментов:
- Условный оператор ref (C# 7.2+) — позволяет возвращать ссылку на элемент коллекции по условию. Пример:
ref int FindRef(int[] arr, int value) { for (int i = 0; i < arr.Length; i++) if (arr[i] == value) return ref arr[i]; throw new IndexOutOfRangeException(); } // Использование: int[] data = { 1, 2, 3 }; ref int item = ref FindRef(data, 2); item = 100; // меняет исходный массив Console.WriteLine(data[1]); // 100 - Ключевое слово fixed — для работы с неуправляемой памятью (редко, но полезно при взаимодействии с WinAPI).
- Атрибут [CallerMemberName] — автоматически подставляет имя вызывающего метода. Отлично для логирования и реализации INotifyPropertyChanged без магии строк.
- Параметр in (C# 7.2) — передача по ссылке только для чтения. Помогает избежать копирования больших структур:
public void Process(in BigStruct data) { // data нельзя изменить внутри метода }
Совет: не гонитесь за всеми фичами сразу. Освойте базовые (??, ?., Pattern Matching) — они покроют 90% повседневных задач. Остальное изучайте по мере необходимости, когда кодовая база станет сложнее.