Почему null не вызывает исключение NullReferenceException при сопоставлении с нулевым типом? - PullRequest
0 голосов
/ 21 января 2019

Я в основном пытаюсь перебрать большой объем данных и преобразовать запрос возвращенных данных в более ограниченный объект в модели представления.

Вместо того, чтобы делать огромный фрагмент кода, я звоню.ForEach () в списке, затем добавление новой записи в список модели представления.

Это прекрасно работает, но есть одно свойство (Адрес), которое является необязательным.

Когда япри достижении необязательного элемента я получаю NullReferenceException, если элемент из БД не имеет записи.

Пример кода:

    var tmp = _context.Person.Include(x => x.Address).ToList();

    tmp.ForEach(x => vm.List.Add(new IndexListItem()
    {
        Name = x.Name,
        Address = x.Address.FirstLine + " " + x.Address.SecondLine,
        ID = x.ID

    }));

С тех пор я узнал отдругой ответ на этом сайте, что если я изменю адресную строку так, чтобы она гласила:

        Address = x.Address?.FirstLine + " " + x.Address?.SecondLine,

Код теперь работает, когда я нажимаю пустую запись в tmp.

Я непонимать это, так как свойство Address в tmp уже допускает нулевые значения, а свойство Address в модели представления допускает нулевые значения, поэтому, почему внезапное изменение строки не возвращает ошибку?

Кроме того,причина для меня не делать x.Address?.FirstLine?, потому что этострока и строки уже обнуляются?

Ответы [ 4 ]

0 голосов
/ 21 января 2019

x.Address?.FirstLine где ? - нулевой оператор распространения, это означает, что если x.Address равно null, установите null для FirstLine.

нулевого кода, эквивалентного распространению

if (x.Address == null)
   return null
else 
   return x.Address.FirstLine

Все переменные ссылочного типа обнуляются.следовательно, присвоение нуля ссылочным типам всегда допустимо.

string - это ссылочный тип в вашем примере.поэтому вы не получите ошибку, потому что string x = null является действительным

0 голосов
/ 21 января 2019

Ваша проблема не в том, что Address имеет значение NULL, и вы пытаетесь присвоить его другому свойству, которое допускает NULL, это то, что вы пытаетесь получить доступ к .FirstLine во что-то, что имеет значение NULL.

Если Address равно нулю, то то, что вы пытаетесь сделать с .FirstLine, является эквивалентом null.FirstLine, который не работает. Ничто не может удержать что-то.

Используемая вами нотация ? влияет только на Address, в основном говоря, если Address равно НЕ null, дайте мне значение .FirstLine, если оно нулевое, тогда дай мне ноль.

0 голосов
/ 21 января 2019

Я не понимаю этого, поскольку свойство Address в tmp уже допускает нулевые значения, а свойство Address в модели представления допускает нулевые значения, поэтому, почему изменение строки внезапно не возвращает ошибку?

Вы путаете сохранение данных с загрузкой данных. Когда вы сохраняете данные в базе данных, null является приемлемым, но при попытке использовать данные null - нет.

Оператор null (?.) позволяет вам «сократить» оператор if, и он будет выглядеть примерно так:

Address = x.Address?.FirstLine + " " + x.Address?.SecondLine,

string Address = "";
if (x.Address != null)
{
    Address += x.Address.FirstLine;
}
// ....

Кроме того, хотя используемый вами код и не относится к вашей проблеме, он крайне неэффективен, вы загружаете 2 таблицы, чтобы получить всего несколько свойств, когда вы можете получить эти свойства непосредственно из базы данных:

var vm = _context.Person
    .Select(x => new IndexListItem
    {
        Name = x.Name,
        Address = x.Address?.FirstLine + " " + x.Address?.SecondLine,
        ID = x.ID
    })
    .ToList();
0 голосов
/ 21 января 2019

Исключение нулевой ссылки в данном конкретном случае вызывается, когда вы пытаетесь получить доступ к свойству, где родительский объект сам по себе равен нулю.

x.Address.FirstLine

, т. Е. В вашем случае Address isnull.

Это не относится к тому, что вы пытаетесь установить (т.е. к модели представления назначения).

Причина, по которой это работает:

x.Address?.FirstLine 

..is потому что «в фоновом режиме» сначала проверяет, является ли Address нулевым.Если это не так, он возвращает FirstLine, а если это так, то возвращается ноль.Это семантически эквивалентно:

if (x.Address == null)
{
    return null;
}
else
{
    return x.Address.FirstLine;
}

Вот сообщение в блоге о введении?.оператор в C # для некоторого фонового чтения: https://blogs.msdn.microsoft.com/jerrynixon/2014/02/26/at-last-c-is-getting-sometimes-called-the-safe-navigation-operator/

...