Обновление: начиная с 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) …
), но с точки зрения синтаксиса его можно считать лучше.