Нужно ли объявлять статичные переменные в C#?
Что проверяют
Понимаете ли вы, что static это глобальное состояние на весь процесс, и отличаете ли безобидные случаи (константы, неизменяемые справочники) от опасных (изменяемое поле, к которому идут несколько потоков и тестов).
Как отвечать
По умолчанию нет. Статическое поле оправдано, когда значение общее для всего приложения и не меняется после инициализации: const, static readonly, потокобезопасный кэш. Изменяемое статическое поле это обычная глобальная переменная со всеми последствиями, и заводить его нужно осознанно.
Что показать дальше:
constвшивается в вызывающую сборку на этапе компиляции, поэтому после обновления библиотеки там останется старое значение;static readonlyчитается в рантайме;static readonly List<T>защищает только ссылку, содержимое менять никто не мешает; для общего доступа берутImmutableArray,ReadOnlyCollectionилиConcurrentDictionary;- инкремент статического счётчика не атомарен, нужен
Interlocked.Incrementилиlock; - статический конструктор выполняется один раз и потокобезопасно, но исключение в нём убивает тип на весь процесс: каждое следующее обращение получает
TypeInitializationException; - вместо статического класса с состоянием обычно правильнее интерфейс и регистрация в контейнере с временем жизни singleton, так зависимость можно подменить.
Где спотыкаются
Оправдывают статику экономией памяти. Экономия тут ничтожная, поле и так одно на тип, а решение принимается по времени жизни и по тому, кто ещё видит это значение.
Заводят статическое поле в веб-приложении под данные запроса. Оно переживает запрос, и один пользователь начинает видеть чужое имя или чужую корзину. Данные на время запроса это scoped-зависимость, а не static; [ThreadStatic] тоже не спасает, потому что после await продолжение выполняется на другом потоке.
Не думают про тесты. Значение протекает между тестами, порядок запуска начинает влиять на результат, а при параллельном прогоне классов падения становятся плавающими и невоспроизводимыми.