[Перевод] ?.: когда свойства в C# могут быть равны null

Чем больше я пишу на C# 6, тем больше убеждаюсь в том, насколько оператор ?. (null coalescing operator) помогает писать чистый простой и понятный код. Сегодня я покажу 4 ситуации, в которых он может быть очень полезен.Большая вложенность Рассмотрим следующую задачку. Имеется поставщик, у поставщика есть контактное лицо, у контактного лица есть домашний адрес, у домашнего адреса есть первая строка, а эту самую первую строку мы и хотим найти. Раньше мне пришлось бы писать код с большим уровнем вложенности, проверяя на null каждое значение в цепочке: var location = default (string); if (vendor!= null) { if (vendor.ContactPerson!= null) { if (vendor.ContactPerson.HomeAddress!= null) { location = vendor.ContactPerson.HomeAddress.LineOne; } } } Но теперь у нас есть C# 6, с ним код можно привести на намного более читаемому виду: var location = vendor?.ContactPerson?.HomeAddress?.LineOne; Оператор ?. сделает так, что как только в одном из свойств цепочки окажется null, дальнейшее вычисление выражения производится не будет. Посмотрим ещё несколько примеров.INotifyPropertyChanged и похожие API Всем нам доводилось видеть классы, которые реализовывают интерфейс INotifyPropertyChanged. В них можно встретить свойства следующего вида: public string Name { get { return name; } set { if (name!= value) { name = value; PropertyChanged (this, new PropertyChangedEventArgs («Name»)); } } }

private string name; Заметили неладное? Код упадёт в случае, если у события INotifyPropertyChanged.PropertyChanged нет подписчиков. В такой ситуации многие разработчики начинают писать так: public string Name { get { return name; } set { if (name!= value) { name = value; if (PropertyChanged!= null) PropertyChanged (this, new PropertyChangedEventArgs («Name»)); } } }

private string name; Окей, стало чутка получше. Вполне возможно, что этот код в большинстве случаев будет работать. Впрочем, race condition никто не отменял: если подписчик отпишется от события в момент после того, как мы проверим PropertyChanged!= null, но до того, как вызовется PropertyChanged, то программа всё-таки упадёт. И произойдёт это в самый неподходящий момент через несколько месяцев после установки приложения у клиента. Давайте исправим эту досадную проблему: сохраним ссылку на PropertyChnaged в локальную переменную handler проверим её на null, после чего будем работать с этой самой локальной переменной, а не с публичным событием PropertyChnaged: public string Name { get { return name; } set { if (name!= value) { name = value; var handler = PropertyChanged; if (handler!= null) handler (this, new PropertyChangedEventArgs («Name»)); } } }

private string name; Ох, кода стало много, сложно всё это запомнит и каждый раз вызывать PropertyChanged грамотно. В большой программе кто-нибудь где-нибудь обязательно забудет сделать все проверки. Что же делать? C# 6 спасёт нас! Все наши проверки легко заменить с помощью оператора ?. и вызова метода Invoke: public string Name { get { return name; } set { if (name!= value) { name = value; PropertyChanged?.Invoke (this, new PropertyChangedEventArgs («Name»)); } } }

private string name; Код получился короче, читается легче, все необходимые проверки выполняются, проблем нет.Управление ресурсами А теперь такая ситуация: имеется объект некоторого типа, описание которого нам известно. Нужно понимать, что этот объект может реализовывать интерфейсы, о которых типу ничего не известно. Обычно это не такая уж и проблема, но что, если объект реализует IDisposable. Представьте себе злого гения, который решил отправить на пенсию одного из своих приспешников. Соответствующий код будет выглядеть следующим образом: public void RetireHenchman () { var disposableMinion = Minion as IDisposable; if (disposableMinion!= null) disposableMinion.Dispose (); Minion = null; } Оператор ?. опять поможет улучшить качество нашего кода: public void RetireHenchman () { (Minion as IDisposable)?.Dispose (); Minion = null; } LINQ-запросы Я нашёл два случая, когда оператор ?. может быть полезен в LINQ-запросах. Случай первый: я хочу создать запрос с использованием метода SingleOrDefault (), а у полученного объекта (если он существует) обратиться к некоторому свойству. Нет ничего проще: var created = members.SingleOrDefault (e => e.name == «dateCreated»)?.content; Случай второй: я хочу вернуть значение null, если исходная последовательность равна null: members?.Select (m => (XElement)XmlValue.MakeValue (m)) Заключение Добавление рассматриваемого оператора заставило меня осознать насколько часто встречаются проверки на null и насколько короче и читаемее можно сделать код с использованием нового синтаксиса. Благодаря ?. я стал писать код иначе. Не могу дождаться, когда же в свет выйдет финальный релиз C# 6, чтобы я мог отдать моим заказчикам новую версию исходников.

© Habrahabr.ru