День сорок четвёртый. #TipsAndTricks

3. Оператор безопасной навигации

Вас ведь тоже бесит постоянно возникающее NullReferenceException, когда происходит обращение к неинициализированному объекту? Чаще всего null-исключение возникает из-за примерно следующего кода:

string name = null;

Console.WriteLine(name);



В большинстве случаев компилятор не позволит вам продолжить, пока вы не исправите код. Но если вы каким-то образом заставите компилятор думать, что переменная имеет значение, а во время выполнения его не окажется, будет выброшено NullReferenceException. Чтобы избежать этого, вы можете сделать следующее:

string name = null;

// Некоторый код

if(name != null) {

Console.WriteLine(name);

}



Это безопасная проверка, которая позволяет убедиться, что значение переменной доступно при её вызове.

Однако в C#6 появился другой способ обойти эту ошибку. Допустим, у вас есть база данных людей, и вы хотите получить данные о трудоустройстве человека, но такие данные отсутствуют, а вы хотите получить название компании-работодателя:

var company = DbHelper.PeopleTable.Find(x => x.id == id).FirstOrDefault().EmploymentHistory.CompanyName;



Если вы попытаетесь это сделать, возникнет ошибка. Как только в цепочке вызовов встречается null, всё пропало. В C#6 появился способ обойти это, используя оператор безопасной навигации после значений или полей, которые могут быть null. Вот так:

var company = DbHelper?.PeopleTable?.Find(x => x.id == id)?.FirstOrDefault()?.EmploymentHistory?.CompanyName;




Этот код будет переходить к следующему элементу в цепочке, только если предыдущий не null. В противном случае вся цепочка вернёт null вместо выброса исключения. Это может быть удобно оставить проверки фреймворку, однако, несмотря на это, вам нужно будет проверить итоговый результат на null.

if(company != null) {

// Дальнейшая обработка

}



Примечание! Стоит отметить, что при всём удобстве этого оператора есть соблазн спрятать плохое проектирование с его помощью, как в последнем примере. Всё-таки несмотря на то, что код не будет выдавать ошибок, связанных с неинициализированными объектами, он может скрыть ошибки, которые вы хотели бы обнаружить и исправить (например, неинициализированный объект DbHelper).



Источник:
https://www.pluralsight.com/guides/tips-for-writing-better-c-code