Хочу рассказать вам историю о том, как синтаксический сахар может отнять у вас несколько часов и привести к ошибкам на продакшене. Так же разберу причины самих ошибок и постараюсь найти варианты, как можно было бы их избежать.
Сразу стоит отметить, что история, которую я опишу ниже, произошла с разработчиком из моей команды, а я лишь выступал в качестве наблюдателя.
Синтаксический сахар в C#
В нашей команде используется язык C#, поэтому мой рассказ будет про его синтаксис.
Синтаксический сахар заменяет длинные и часто используемые конструкции кода, делает их более короткими и быстро читаемыми, облегчает и ускоряет разработку.
Здесь стоит отметить и другое мнение: существуют люди, которые считают, что синтаксический сахар только усложняет код, делая его менее читаемым.
Я придерживаюсь данного мной определения, хотя опыт показал, что не всё так однозначно. Разберем на примерах:
Примеры:
-
Конструкция
new () {1, 2}заменяетnew List() {1, 2} -
Оператор
+=заменяет конструкцию-
number += 1=> -
number = number + 1
-
-
А оператор
??=вообще имеет долгую историю-
foo ??= "Строка была равна null"=> -
foo = foo ?? "Строка была равна null"=> -
foo = foo is null ? "Строка была равна null" : foo=> -
if (foo is null)
{
foo = "Строка была равна null";
}
-
Эти примеры лишь малая часть всех тех конструкций, которые иcпользуются в C#. С каждой новой версией языка появляется всё больше новых конструкций и нужно пристально следить, чтобы ничего не упустить.
Неожиданные Null Reference Exception
Итак, перейдем к истории. Всё началось с того момента, когда в нашем проекте начали «выстреливать» ошибки ... var result = new ExampleClass { ExString = "Тут не должно быть взрыва", ExList = { 0, 1 }, ExString2 = "И тут", ExInt = 24 }; ...
public class ExampleClass { public string? ExString { get; set; } public List<int>? ExList { get; set; } public string? ExString2 { get; set; } public int ExInt { get; set; } }
Наверное, я оставил очень прозрачные подсказки в коде, чтобы вы смогли догадаться, из-за чего выбрасывалась ошибка. Но в моменте было совсем не ясно, особенно когда ты пытаешься быстро разобраться в ситуации из-за ошибок на продакшене. Можно обратить внимание на весьма странный синтаксис в коде. Выше я приводил пример того, как конструкция Но причём тут NRE? А всё дело в том, что Так как Пояснение
... var result = new ExampleClass { ... ExList = { 0, 1 }, ... }; ...new() {0, 1} заменяет new List() {0, 1}. Можно заметить, что {0, 1} уж очень похоже на new() {0, 1}.
Первый раз, глядя на эту конструкцию, в голову совсем не приходит мысль о том, что тут что-то не так. Скорее возникает мысль: «Наверное, это новый синтаксис». После 10 минут интенсивного просмотра кода было принято решение заменить {0, 1} на new() {0, 1}. И, о чудо, ошибки исчезли.{0, 1} заменяет конструкцию .Add() И вот эти два блока кода оказываются идентичными:// 1 var result1 = new ExampleClass { ExList = { 1, 2 }, ExString = "Привет", ExInt = 24 }; // 2 var result2 = new ExampleClass { ExString = "Привет", ExInt = 24 }; result.ExList.Add(1); result.ExList.Add(2);ExList при инициализации равен null, то при попытке вызывать null.Add() мы получаем https://habr.com/ru/articles/764586/
Добавить комментарий