C# оператор объединения
У меня есть класс со строковым свойством. Я использую оператор coalesce при чтении из него, поскольку он может быть нулевым, но он все равно выдает мне NullRefrenceExeption.
string name = user.Section.ParentSection.Name ?? string.Empty;
Чтобы быть более конкретным, это ".ParentSection", который является нулевым, так ли это, потому что у него даже нет ".name"? Если это так, я должен сначала проверить ".ParentSection" с блоком if?
Я предполагаю, что в операторе Coalesce есть что-то, чего я не понимаю, надеюсь, кто-то сможет пролить свет на то, что здесь происходит не так.
9 ответов
Чтобы быть более конкретным, это ".ParentSection", который является нулевым, так ли это, потому что у него даже нет ".name"?
Да.
Если это так, я должен сначала проверить ".ParentSection" с блоком if?
Да.
Вам нужно будет проверить, если Section
а также ParentSection
являются нулевыми Вы можете использовать для этого оператор if или написать метод расширения, например:
public static class MaybeMonad
{
public static TOut With<TIn, TOut>(this TIn input, Func<TIn, TOut> evaluator)
where TIn : class
where TOut : class
{
if (input == null)
{
return null;
}
else
{
return evaluator(input);
}
}
}
Вы бы использовали этот метод так:
string name = user.With(u => u.Section)
.With(s => s.ParentSection)
.With(p => p.Name) ?? string.Empty;
Я думаю, что это намного чище, чем if-заявление с большим количеством &&
,
Некоторое дальнейшее чтение: http://www.codeproject.com/Articles/109026/Chained-null-checks-and-the-Maybe-monad
Доступ к вложенным свойствам небезопасен, если какой-либо из объектов, к которым осуществляется доступ, null
это бросит NullReferenceException
, Вам придется явно проверить, чтобы внешние объекты не были нулевыми.
Например:
string name = string.Empty;
if(user!=null && user.Section!=null && user.Section.ParentSection !=null)
name = user.Section.ParentSection.Name ?? string.Empty;
В общем, я бы старался избегать вложенного доступа к свойствам, вы нарушаете закон Деметры. Некоторый рефакторинг может сделать это ненужным в первую очередь.
Вы должны проверить, если user
, user.Section
, или же user.Section.ParentSection
являются нулевыми, прежде чем вы можете использовать оператор объединения нулей на свойство user.Section.ParentSection
,
??
Оператор проверяет, является ли левая сторона нулевой, и если да, возвращает правую, если не левую. В вашем случае левая сторона - это свойство "Имя" в объекте. user.Section.ParentSection
и это ноль.
В этих случаях либо подумайте о том, что может быть нулевым, либо сделайте что-то вроде этого:
string name = user == null
|| user.Section == null
|| user.ParentSection == null
|| user.Section.ParentSection.Name == null
? string.Empty
: user.Section.ParentSection.Name;
(да, это ужасно, я знаю)
Скорее всего user
или же user.Section
или же user.Section.ParentSection
является нулевым значением
??
Оператор не запрещает такие проверки, как:
if (user != null && user.Section != null && user.Section.ParentSection != null){
Убедитесь, что все до свойства строки допустимо и существует, тогда вы можете использовать ??
, Ты не можешь позвонить (null).Name
, независимо от того, сколько раз вы пытаетесь.
Нулевой оператор слияния принимает оператор как:
a = b ?? c;
Это говорит о том, что "оцените b; если оно имеет ненулевое значение, присвойте его a. В противном случае присвойте значение c a".
Однако в вашем b вы используете пользовательский объект, который может быть нулевым, который имеет объект раздела, который может быть нулевым, который имеет свойство родительского раздела, которое может быть нулевым, и имеет свойство имени, которое может быть нулевым. Если вы хотите проверить все это (и, как правило, вам следует), то вы можете сделать что-то вроде:
string name = string.Empty;
if (user != null &&
user.Section != null &&
user.Section.ParentSection != null)
{
name = user.Section.ParentSection.Name ?? string.Empty;
}
Как только проверка IF завершится неудачей, она больше не будет проверяться, и поэтому вы не получите исключение NullReferenceException, если предположите, что объект присутствует, а затем попытаетесь получить доступ к одному из его свойств.
Вероятно, лучше сделать что-то вроде этого:
if(user!=null && user.Section!=null && user.Section.ParentSection!=null)
{
string name = user.Section.ParentSection.Name ?? string.Empty;
}
Да, вы должны проверить, если Section
или же ParentSection
равны нулю перед проверкой Name