Оновлення: Починаючи з 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
...
}
Я особисто не став би цього робити з наступних причин:
- Це не виглядає приємно.
- Він використовує обробку винятків, яка повинна орієнтуватися на виняткові ситуації, а не те, що, як ви очікуєте, трапляється часто під час звичайного курсу роботи.
NullReferenceException
s, ймовірно, ніколи не слід чітко ловити. (Дивіться це запитання .)
Так чи можливо за допомогою якогось методу розширення чи це мовна особливість, [...]
Це майже напевно повинно бути мовною особливістю (яка доступна в 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) …
), але це може бути оцінено приємніше з точки зору синтаксису.