Introduction: Why Your Code Makes a Senior Twitch?
\n\nYou submitted a pull request. Five minutes passed. A message pops up in the chat: "How about we rewrite this block?" and a dozen comments under every other line. Sound familiar? If you write in C# and work in a team, code review is not just a checkbox in Jira. It's a moment of truth.
\n\nI've collected typical comments that seniors leave on C# code reviews. This isn't about syntax — it's about mindset. About turning "just working code" into code that no one wants to rewrite on the first Friday.
\n\nLet's dive into the C# antipatterns that annoy even the calmest team leads.
\n\n1. Magic Numbers and Strings: "What Does That Mean?"
\n\nThe most common comment on a C# code review is a question about numbers. You write if (status == 3), and a senior immediately asks: "What is 3? Is it the 'Processing' status or 'Deleted'?"
Bad:
\nif (order.Status == 3 && days > 7)\n{\n CancelOrder(order);\n}\n\n\nGood:
\nprivate const int OrderStatusCancelled = 3;\nprivate const int MaxDaysBeforeAutoCancel = 7;\n\nif (order.Status == OrderStatusCancelled && days > MaxDaysBeforeAutoCancel)\n{\n CancelOrder(order);\n}\n\n\nEven better — move it to an enum. Seniors love readable code where you don't have to dig into the database to understand the business logic. This is a basic code review C# rule: the code should speak for itself.
\n\n2. Async Void — The Silent Application Killer
\n\nIf you write async void anywhere except event handlers (e.g., in WPF or WinForms), get ready for a big minus. Async void cannot be tracked — an exception will fall into the void and crash the process.
Bad:
\npublic async void LoadData()\n{\n var data = await _repository.GetDataAsync();\n // If this fails — the application crashes without an error message\n}\n\n\nGood:
\npublic async Task LoadDataAsync()\n{\n var data = await _repository.GetDataAsync();\n}\n\n\nDuring a C# code review, a senior will definitely point this out. Remember: async Task is your friend, async void is your enemy (except for events).
3. Godzilla Classes: Single Responsibility Principle
\n\nYou open a file, and it has 2000 lines. One class does everything: accesses the database, sends emails, generates reports, and even makes coffee. This is a classic C# antipattern — the God Object.
\n\nA senior on a C# code review will say: "Let's break this into several classes." And they'll be right.
\n\nExample of a violation:
\npublic class OrderService\n{\n public void ProcessOrder(Order order)\n {\n // 1. Validation\n // 2. Save to DB\n // 3. Send email\n // 4. Logging\n }\n}\n\n\nHow it should be:
\npublic class OrderProcessor\n{\n private readonly IOrderValidator _validator;\n private readonly IOrderRepository _repository;\n private readonly INotificationService _notificationService;\n\n public OrderProcessor(\n IOrderValidator validator,\n IOrderRepository repository,\n INotificationService notificationService)\n {\n _validator = validator;\n _repository = repository;\n _notificationService = notificationService;\n }\n\n public async Task ProcessOrderAsync(Order order)\n {\n _validator.Validate(order);\n await _repository.SaveAsync(order);\n await _notificationService.SendConfirmationAsync(order);\n }\n}\n\n\nThis isn't just "pretty." It's testable. You can mock the repository and test only the processing logic. C# refactoring in this style is a must-have for any project.
\n\n4. Exceptions as Control Flow
\n\n