Оновлення: Починаючи з Visual Studio 2015, компілятор C # (мовна версія 6) тепер розпізнає ?.оператора, що робить «глибоку перевірку нуля» вітерцем. Детальніше див. У цій відповіді .
Окрім повторного проектування вашого коду, як-от запропонована
ця видалена відповідь , ще одним (хоч і жахливим) варіантом було б використання try…catchблоку, щоб перевірити, чи NullReferenceExceptionвиникає колись під час глибокого пошуку властивостей.
try
{
var x = cake.frosting.berries.loader;
...
}
catch (NullReferenceException ex)
{
// either one of cake, frosting, or berries was null
...
}
Я особисто не став би цього робити з наступних причин:
- Це не виглядає приємно.
- Він використовує обробку винятків, яка повинна орієнтуватися на виняткові ситуації, а не те, що, як ви очікуєте, трапляється часто під час звичайного курсу роботи.
NullReferenceExceptions, ймовірно, ніколи не слід чітко ловити. (Дивіться це запитання .)
Так чи можливо за допомогою якогось методу розширення чи це мовна особливість, [...]
Це майже напевно повинно бути мовною особливістю (яка доступна в C # 6 у формі операторів .?та ?[]операторів), якщо тільки C # вже не має більш складних лінивих оцінок або якщо ви не хочете використовувати рефлексію (яка, ймовірно, також не є гарна ідея з міркувань продуктивності та безпеки безпеки).
Оскільки немає можливості просто перейти cake.frosting.berries.loaderдо функції (вона буде оцінена і викинути нульовий посилання на виключення), вам доведеться реалізувати загальний метод пошуку таким чином: Він бере об’єкти та назви властивостей, щоб шукати:
static object LookupProperty( object startingPoint, params string[] lookupChain )
{
// 1. if 'startingPoint' is null, return null, or throw an exception.
// 2. recursively look up one property/field after the other from 'lookupChain',
// using reflection.
// 3. if one lookup is not possible, return null, or throw an exception.
// 3. return the last property/field's value.
}
...
var x = LookupProperty( cake, "frosting", "berries", "loader" );
(Примітка: код відредагований.)
Ви швидко бачите кілька проблем з таким підходом. По-перше, ви не отримуєте будь-якого типу безпеки та можливого боксу значень властивостей простого типу. По-друге, ви можете або повернутися, nullякщо щось піде не так, і вам доведеться перевірити це у своїй функції виклику, або ви кинете виняток, і ви повернетесь туди, звідки почали. По-третє, це може бути повільним. По-четверте, це виглядає гірше, ніж те, з чого ви почали.
[...], чи це просто погана ідея?
Я б або залишився з:
if (cake != null && cake.frosting != null && ...) ...
або піти з вищезазначеною відповіддю Мехрдада Афшарі.
PS: Коли я писав цю відповідь, я, очевидно, не вважав дерева виразів лямбда-функцій; див., наприклад, @driis відповідь на рішення в цьому напрямку. Він також ґрунтується на певному роздумі і, таким чином, може не працювати так само просто, як простіше рішення ( if (… != null & … != null) …), але це може бути оцінено приємніше з точки зору синтаксису.