Почему code style — это не про «я так вижу»
Вы когда-нибудь открывали чужой код на C# и чувствовали себя археологом, раскапывающим руины древнего храма? public int a;, var x = GetSmth() без контекста и методы длиной в 400 строк. Если да — вы знаете, как болит голова команды без единого code style.
Работа в команде — это не только про Git и code review. Это про то, что ваш код читают другие люди. И если вы пишете для себя, то code style для C# — это скучная бюрократия. Но если вы пишете для команды — это спасение нервов, времени и продакшена.
В этой статье мы разберём, какие конвенции C# реально работают в 2024 году, как внедрить их без боли и почему EditorConfig — ваш лучший друг. Поехали.
Базовые правила: о чём договариваться в первую очередь
1. Именование (naming conventions)
В C# есть жёсткие стандарты, но команды часто их нарушают. Вот золотой минимум, который принимает 90% .NET-команд:
- PascalCase — для классов, методов, свойств, публичных полей:
public class UserService,public string GetUserName(). - camelCase — для локальных переменных, параметров методов, приватных полей (часто с префиксом
_):private int _userId;,var userName = "Alex";. - Избегайте венгерской нотации —
strName,intCount— это прошлый век. Тип переменной должен быть очевиден из контекста. - Не сокращайте без необходимости —
GetUsrInf()хуже, чемGetUserInformation(). Исключение: общепринятые аббревиатуры (IO,UI,DTO).
// Плохо
public class user_service
{
public int id;
public string nm;
private string _data;
public string GetData() => _data;
}
// Хорошо
public class UserService
{
public int Id { get; }
public string Name { get; }
private readonly string _userData;
public string GetUserData() => _userData;
}
2. Форматирование: пробелы, скобки, пустые строки
Споры о том, ставить ли пробел перед двоеточием в catch (Exception e) — бесконечны. Поэтому используйте автоматические инструменты. Но базовые договорённости всё же нужны:
- Отступы — 4 пробела (табуляцию в C# используют редко, но если команда выбрала табы — это нормально).
- Фигурные скобки — всегда на новой строке (Allman style). Это стандарт для C#.
- Одна пустая строка между методами. Две — между классами.
// Плохо (скобки на той же строке — это Java, не C#)
public void Process() {
var result = Calculate();
return result;
}
// Хорошо (Allman style)
public void Process()
{
var result = Calculate();
return result;
}
Продвинутые конвенции: на чём чаще всего спотыкаются
3. Использование var
Одна из вечных дискуссий. Правило простое: используйте var, когда тип очевиден из правой части. Если нет — пишите явно.
// Можно var
var users = GetUsers(); // тип очевиден
var dictionary = new Dictionary<string, int>(); // длинное объявление
// Лучше явно
User user = GetUserById(id); // неочевидно, что возвращается User
Dictionary<string, int> result = ParseData(); // тоже неочевидно
Если ваша команда не любит var — просто договоритесь. Главное — единообразие.
4. Работа с LINQ
LINQ — мощный, но коварный инструмент. Частая ошибка — цепочки длиной в 10 методов, которые читаются как заклинание. Договоритесь:
- Разбивайте длинные LINQ-выражения на несколько строк.
- Не злоупотребляйте
.Select()там, где нужен простой foreach. - Избегайте побочных эффектов внутри LINQ (например, вызова
Console.WriteLine()внутри.ForEach()— это антипаттерн).
// Плохо: всё в одну строку
var result = data.Where(x => x.IsActive).Select(x => new { x.Name, x.Age }).OrderBy(x => x.Age).ToList();
// Хорошо: читаемо
var activeUsers = data.Where(x => x.IsActive);
var userInfos = activeUsers.Select(x => new { x.Name, x.Age });
var sorted = userInfos.OrderBy(x => x.Age).ToList();
5. Обработка ошибок
Типичная проблема — пустые catch блоки. Если вы ловите исключение — либо логируйте, либо пробрасывайте дальше. Не глотайте ошибки молча.
// Плохо
try
{
ProcessData();
}
catch (Exception)
{
// ничего не делаем
}
// Хорошо
try
{
ProcessData();
}
catch (Exception ex)
{
Logger.LogError(ex, "Ошибка при обработке данных");
throw; // или throw new CustomException("...", ex);
}
Инструменты: как заставить команду соблюдать code style
Договорённости — это хорошо, но люди забывают. Поэтому нужны автоматические инструменты.
EditorConfig
Файл .editorconfig в корне проекта — это база. Он подхватывается Visual Studio, Rider и VS Code. Пример минимального набора:
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.cs]
csharp_new_line_before_open_brace = all
csharp_prefer_braces = true
csharp_style_var_for_built_in_types = true
csharp_style_var_when_type_is_apparent = true
.NET Analyzers и StyleCop
Включите в проект NuGet-пакет StyleCop.Analyzers или используйте встроенные анализаторы Roslyn. Они подсветят нарушения прямо в редакторе.
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
Настройте правила в .editorconfig или в отдельном файле stylecop.json. Например, можно отключить обязательные XML-комментарии для приватных методов — они не всегда нужны.
Code review checklist
Создайте чек-лист для пул-реквестов. Вот минимальный набор