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

Другие вопросы по тегам