В С# есть ли чистый способ проверки нескольких уровней нулевых ссылок
Например, если я хочу вызвать следующее:
person.Head.Nose.Sniff()
то, если я хочу быть в безопасности, я должен сделать следующее:
if(person != null)
if(person.Head != null)
if(person.Head.Nose != null)
person.Head.Nose.Sniff();
Есть ли более простой способ формулировки этого выражения?
Ответы
Ответ 1
Есть ли более простой способ формулировки этого выражения?
С С# 6 вы можете использовать оператор с нулевым условием ?
.
Пример кода
Это ваш исходный код, упакованный в метод, и если Sniff()
всегда возвращает true
:
public bool PerformNullCheckVersion1(Person person)
{
if (person != null)
if (person.Head != null)
if (person.Head.Nose != null)
return person.Head.Nose.Sniff();
return false;
}
Это ваш код, переписанный оператором с нулевым условием С# 6:
public bool PerformNullCheckVersion2(Person person)
{
return person?.Head?.Nose?.Sniff() ?? false;
}
??
- это оператор с нулевым коалесцированием и не связан с вашим вопросом.
В качестве полного примера см.
https://github.com/lernkurve/Stackoverflow-question-3701563
Ответ 2
Сначала вы можете использовать короткое замыкание в логических логических операциях и сделать что-то вроде:
if (person != null && person.Head != null && person.Head.Nose != null)
{
person.Head.Nose.Sniff();
}
Также обратите внимание, что то, что вы делаете, противоречит руководящему принципу разработки программного обеспечения, известного как Закон Деметры.
Ответ 3
Здесь другая реализация в соответствии с упомянутой также проверкой Fluent Parameter Validation: Цепочки с нулевыми проверками и монадой Maybe
Ответ 4
Не совсем, кроме
if (person != null && person.Head != null && person.Head.Nose != null)
Ответ 5
Вы можете использовать null objects вместо нулевых значений. Sniff
тогда ничего не сделает, если любые объекты в цепочке вызовов являются нулевыми объектами.
Это не вызовет исключения:
person.Head.Nose.Sniff();
Ваши нулевые классы могут выглядеть так (вы также можете использовать их как синглеты и иметь интерфейсы для IPerson
, IHead
и INose
):
class NullPerson : Person {
public override Head Head { get { return new NullHead(); }
}
class NullHead : Head {
public override Nose Nose { get { return new NullNose(); }
}
class NullNose : Nose {
public override void Sniff() { /* no-op */ }
}
В качестве дополнительной заметки в Oxygene есть operator для этого:
person:Head:Nose:Sniff;
Ответ 6
Вы можете использовать Свободная проверка параметров
Ответ 7
Лучше всего использовать оператор &&
вместо вложенных операторов if
:
if (person != null && person.Head != null && person.Head.Nose != null)
{
person.Head.Nose.Sniff();
}
Обратите внимание, что технически вы можете выполнить аналогичную нулевую проверку с помощью дерева выражений. У вашего метода будет такая подпись:
static bool IsNotNull<T>(Expression<Func<T>> expression);
... который позволит вам написать код, выглядящий примерно так:
if (IsNotNull(() => person.Head.Nose))
{
person.Head.Nose.Sniff();
}
Но это будет связано с отражением и, как правило, намного сложнее следовать каким-либо углубленным образом по сравнению с методом &&
.
Ответ 8
Я бы избавился от любого использования null
и сделал что-то вроде этого:
((Nose)person.BodyParts[BodyPart.Nose]).Sniff();
Для этого потребуется какая-то база class
или interface
.
public abstract class BodyPart
{
public bool IsDecapitated { get; private set; }
public BodyPart(bool isDecapitated)
{
IsDecapitated = isDecapitated;
}
}