C # оператор объединения - PullRequest
2 голосов
/ 28 марта 2012

У меня есть класс со строковым свойством. Я использую оператор coalesce при чтении из него, поскольку он может быть нулевым, но он все равно выдает мне NullRefrenceExeption.

string name = user.Section.ParentSection.Name ?? string.Empty;

Чтобы быть более точным, это ".ParentSection", который является нулевым, так ли это, потому что у него даже нет ".name"? Если это так, я должен сначала проверить ".ParentSection" с блоком if?

Полагаю, что в операторе Coalesce есть что-то, чего я не понимаю, надеюсь, кто-то сможет пролить свет на то, что здесь происходит не так.

Ответы [ 9 ]

7 голосов
/ 28 марта 2012

Чтобы быть более точным, это ".ParentSection", который является нулевым, так что он даже не имеет ".name"?

Да.

Если это так, должен ли я сначала проверить ".ParentSection" с помощью блока if?

Да.

4 голосов
/ 28 марта 2012

Вам нужно проверить, равны ли значения 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

3 голосов
/ 28 марта 2012

Доступ к вложенным свойствам небезопасен, если какой-либо из объектов, к которым получен доступ, равен null, это выдаст NullReferenceException.Вам придется явно проверить, чтобы внешние объекты не были нулевыми.

Например:

string name = string.Empty;
if(user!=null && user.Section!=null && user.Section.ParentSection !=null)
   name = user.Section.ParentSection.Name ?? string.Empty;

В общем, я бы старался избегать вложенного доступа к свойствам, вы нарушаете Закон Деметры .Некоторый рефакторинг может сделать это ненужным в первую очередь.

3 голосов
/ 28 марта 2012

Необходимо проверить, равны ли значения user, user.Section или user.Section.ParentSection нулями, прежде чем использовать оператор объединения нулей для свойства user.Section.ParentSection.

2 голосов
/ 28 марта 2012

Оператор ?? проверяет, является ли левая сторона нулевой, и, если это так, возвращает правую, если не левую.В вашем случае левая сторона - это свойство «Имя» в объекте user.Section.ParentSection, и оно равно нулю.

В этих случаях либо подумайте, что может быть нулевым, либо сделайте что-то вроде этого:1006 *

(да, это ужасно, я знаю)

1 голос
/ 28 марта 2012

Скорее всего, user или user.Section или user.Section.ParentSection - это нулевое значение.

Оператор ?? не запрещает проверки типа:

if (user != null && user.Section != null && user.Section.ParentSection != null){

Убедитесь, чточто все, вплоть до строкового свойства, является действительным и существует, тогда вы можете использовать ??.Вы не можете позвонить (null).Name, независимо от того, сколько раз вы пытаетесь.

0 голосов
/ 28 марта 2012

Оператор слияния NULL принимает оператор типа:

a = b ?? c;  

То, что он говорит: «оцените b; если он имеет ненулевое значение, присвойте его a. В противном случае присвойте значение cа».

Однако в пределах вашего b вы используете пользовательский объект, который может быть нулевым, с объектом раздела, который может быть нулевым, с родительским свойством раздела, которое может быть нулевым, с именемсвойство, которое может быть нулевым.Если вы хотите проверить все это (и, как правило, вам следует), вы можете сделать что-то вроде:

string name = string.Empty;  
if (user != null &&  
     user.Section != null &&  
     user.Section.ParentSection != null)  
{  
  name = user.Section.ParentSection.Name ?? string.Empty;  
}

Как только проверка IF не удастся, она больше не будет проверяться, и поэтому вы не получитеNullReferenceException, если вы предполагаете, что объект присутствует, а затем пытаетесь получить доступ к одному из его свойств.

0 голосов
/ 28 марта 2012

Вероятно, лучше сделать что-то вроде этого:

if(user!=null && user.Section!=null && user.Section.ParentSection!=null)
{
     string name = user.Section.ParentSection.Name ?? string.Empty;
}
0 голосов
/ 28 марта 2012

Да, прежде чем проверять Name

, вам нужно проверить, равны ли значения Section или ParentSection нулями
...