C#MiddleExperience

Какие ошибки делают разработчики, переходящие на C# с другого языка или стека?

С Python: игнорирование типов, синхронный код в async-контексте. С Java: избыточные интерфейсы, путаница Optional vs Nullable. С JS/TS: дедлок через .Result вместо await. Системные: captive dependency в DI, не закрытые IDisposable-ресурсы. Лечится Roslyn-анализаторами и DI ValidateOnBuild.

Типичные ошибки при переходе на C# с другого языка

С Python

  • Игнорирование типов. Python-разработчики привыкают к динамической типизации и используют object или dynamic вместо конкретных типов, теряя преимущества компилятора.
  • Синхронный код вместо async. В Python asyncio — опциональный; в ASP.NET Core async — стандарт. Блокирующие вызовы (Thread.Sleep, синхронные HTTP) приводят к thread pool starvation.
  • Неверная работа с None/null. Python-разработчики забывают про nullable reference types и ArgumentNullException.ThrowIfNull, что приводит к NRE в production.

С Java

  • Переиспользование Java-паттернов. В Java принято оборачивать каждый класс в интерфейс; в C# это избыточно для приватных реализаций. Избыток абстракций усложняет код без выгоды.
  • Checked exceptions. В Java checked exceptions обязательны к обработке; в C# все исключения unchecked — без явных null-checks и guard clauses ошибки проявляются позже.
  • Путаница Optional vs Nullable. Java Optional — обёртка-объект; C# nullable (T?) — языковой механизм без дополнительных аллокаций.

С JavaScript/TypeScript

  • Прототипная vs классовая модель. JS-разработчики иногда ищут прототипное наследование; в C# наследование строгое, без динамического добавления методов в runtime.
  • Async/await похоже, но разное. В JS любой Promise можно await без объявления функции async; в C# нужен async на метод, и смешивание с .Result вызывает дедлок.
  • Строгая типизация дженериков. TypeScript допускает covariance почти везде; C# различает in/out variance на интерфейсах — IEnumerable<T> ковариантен, List<T> — нет.

Системные ошибки независимо от языка

  • Captive dependency в DI. Singleton, захвативший Scoped DbContext — классика, которую компилятор не поймает.
  • Blocking call в async context. task.Result или task.Wait() в методе с SynchronizationContext = дедлок.
  • Забытый using. Открытые HttpClient, FileStream, DbConnection без using исчерпывают системные ресурсы.

Как предотвращать

Code review с C#-specific checklists, Roslyn-анализаторы (Microsoft.CodeAnalysis.NetAnalyzers, SonarAnalyzer.CSharp), включённый <Nullable>enable</Nullable> и <TreatWarningsAsErrors>true</TreatWarningsAsErrors> в csproj, а также DI-валидация через ValidateOnBuild = true.

Подводные камни

  • Не превращайте ответ в список запретов — объясняйте, почему ошибка возникает и как её обнаружить рано.
  • Самые дорогие ошибки проявляются не на ревью, а под нагрузкой: thread pool starvation, LOH fragmentation, captive dependency.
  • Анализаторы ловят много, но не всё: дедлоки и GC-паузы требуют нагрузочного тестирования.

What hurts your answer

  • Перечислять ошибки без объяснения причин
  • Не отличать beginner mistakes от production failure modes
  • Не предлагать процесс, который предотвращает повторение ошибок

What they're listening for

  • Знает типичные ошибки при работе с C#
  • Понимает причины ошибок
  • Предлагает практики prevention и early detection

Related topics