«Null-Safe» точечная нотация в VB.NET или существует ли она на каком-либо языке? 'безопасный оператор разыменования' или эквивалент с использованием LINQ?

Я ищу «безопасную» точечную нотацию в VB.net. Существует ли такая вещь - на VB.NET или на любом другом языке? Я хочу иметь возможность при использовании устаревших объектов, не допускающих значения NULL, решать такую ​​проблему, как:

если есть план, если есть случай, если в нем есть человек, его супруга, иначе ничего (VBSpeak for Null).

и избегайте этого:

Dim Spouse as Person = Nothing
if Case.Plan isnot nothing then
    if Case.Plan.Person isnot Nothing
        Spouse = Case.Plan.Person.Spouse
    end if
end if

и сделайте так:

Dim Spouse as Person = Case~Plan~Person~Spouse

Где '~' - это моя искомая «безопасная» точечная нотация, которая немедленно возвращает ноль при обнаружении первого нулевого объекта вместо того, чтобы генерировать исключение?

Конечно, более распространенные для этой проблемы:

dim MyVar as string = XMLDoc.DocumentElement.SelectSingleNode("Name").InnerText

и не желая ничего вместо исключения, когда Name не существует.

Редактировать:

Есть ли способ решить эту проблему с помощью LINQ для объектов или LINQ для XML?


person FastAl    schedule 21.03.2011    source источник
comment
Хотя я бы согласился на запросы LINQ, если такой вещи не существует, мне любопытнее всего остального. И некоторые огромные старые программы все еще ждут обновления с .Net2.0 (не мой выбор :-) Для более новых программ мы стараемся использовать другие решения.   -  person FastAl    schedule 21.03.2011
comment
см. также stackoverflow.com/questions/1196031/ и других результатах поиска для безопасного оператора разыменования   -  person AakashM    schedule 21.03.2011
comment
@AakashM - AHH 'безопасный оператор разыменования' Я знал, что у него было правильное название, что мой слабый google-fu пропал!   -  person FastAl    schedule 21.03.2011


Ответы (4)


VB.NET 14 представил оператор с условным нулевым значением для решения этой проблемы. Этот оператор также замыкает накоротко.

Dim Spouse as Person = Case?.Plan?.Person?.Spouse

Используется для проверки нулевого значения перед выполнением операции доступа к члену (?.) Или индексации (? [). Эти операторы помогают вам писать меньше кода для обработки нулевых проверок, особенно для спуска в структуры данных.

То же самое работает в C #:

Person spouse = Case?.Plan?.Person?.Spouse;
person Saragis    schedule 07.08.2015

Я обычно использовал методы расширения для такого рода вещей, очень похожие на то, на что указал AakashM. Хорошим примером этого является длина строки. Поскольку функция LENGTH является методом экземпляра, если вы вызовете ее для объекта с нулевой строкой, вы выбросите.

Но запрограммируйте метод расширения LEN для строкового класса, который проверяет значение null, и вы можете заставить его возвращать 0 (я считаю, что нулевые строки имеют длину 0 практически все время, но это тема для другого потока).

Используя ту же логику, вы можете реализовать IsNotNull или, может быть, IsValid. основная проблема будет состоять в том, чтобы "остановить" дальнейшее разрешение собственности (например, от случая к плану)

методы в вышеупомянутом потоке используют Lambdas, что дает довольно громоздкий синтаксис, если вы спросите меня. Я подозреваю, что можно было бы, если тест IsNotNull дал нулевое значение, вернуть объект Proxy, который заменяет ноль, и просто разрешил бы любой вызов метода, который вы делаете для него, также в нуль. Но для этого потребуется динамический прокси, который сам по себе беспорядочный.

person DarinH    schedule 21.03.2011
comment
Полностью согласен. Я использую Len, Mid, Left и все старые строковые функции VB, хотя они неприятно основаны на 1 из-за стоимости дополнительного кода защиты или, что еще хуже, ошибок в версиях строковых объектов. У них есть и другие хорошие защиты. На самом деле для MsgBox(Mid("", 2, 5)) было бы «правильным» генерировать исключение, как это делает string.substring - к сожалению, в реальном программировании вы хотите "" 99% времени - это то, что возвращает Mid !!! - person FastAl; 21.03.2011
comment
Да, одна база - это немного затруднительно в .net, поскольку все остальное - нулевое. Однако, используя методы расширения, вы можете сделать эти функции основанными на 0 или 1, как вам удобнее. Я ХОЧУ, чтобы у метода расширения был способ переопределить метод экземпляра. тогда я мог бы переопределить метод .net LENGTH на тот, который работает больше так, как мне нужно, но, увы, это невозможно. - person DarinH; 21.03.2011

Вот и все, что касается синтаксиса VB.NET, в нем нет ничего похожего на нулевой оператор объединения, как в C # ?? оператор. Функция Iif () может писать более компактные операторы If, но они редко работают для пустых ссылок, поскольку вычисляются оба аргумента.

В общем, старайтесь отдавать предпочтение пустым ссылкам в качестве помощи при отладке. Они выдают приятное исключение, когда какой-то другой код, который вы не писали, вызывает ваш, но испортил что-то вроде инициализации. Молчаливое распространение ошибок программирования затрудняет диагностику сбоя. Как исключение NullReferenceException, которое далеко от причины. Или, что еще хуже, плохие данные. Возможно, вы могли бы обратиться к своему сценарию с помощью NotAPlan и объекта NoSpouse, объектов, которые существуют исключительно во избежание исключений нулевых ссылок и логически означают «не назначен план, не определен супруг». В противном случае ссылка, которая может быть нулевой, является не чем иным, как ссылкой + логическим значением. Не пропускайте bool.

person Hans Passant    schedule 21.03.2011
comment
В VB также есть операция объединения с нулевым значением: оператор If с двумя аргументами: msdn.microsoft.com/en-us/library/bb513985.aspx - person Meta-Knight; 21.03.2011
comment
Но я не думаю, что если или ?? операторы вообще могут помочь, когда у вас есть несколько нулевых проверок. - person Meta-Knight; 21.03.2011
comment
Об операторе If: он существует только в версии 2008 года и новее. - person Meta-Knight; 21.03.2011

В версиях VB до 14 (Visual Studio 2015) отсутствует нуль-безопасная точечная нотация.

Более приятный способ справиться с возможными нулевыми значениями без слишком большого количества if - использовать AndAlso (короткое замыкание And):

If Case.Plan IsNot Nothing _
AndAlso Case.Plan.Person IsNot Nothing _
AndAlso Case.Plan.Person.Name = "Something" Then
    'Do something here
End If

Другой вариант - использовать шаблон нулевого объекта. Но это возможно только с вашими собственными типами данных и потребует некоторых изменений в вашем коде.

Изменить:

Чтобы ответить на ваш вопрос о LINQ, он не может вам в этом помочь. Цель LINQ - помочь вам запрашивать наборы данных (списки, массивы и т. Д.). Если вы попытаетесь запросить данные с помощью LINQ, у вас будет такая же проблема, если один из ваших объектов имеет значение NULL.

person Meta-Knight    schedule 21.03.2011
comment
Я должен пояснить, что неудачный ответ на оба моих вопроса - НЕТ и НЕТ. Ответ отмечен здесь, потому что я уже предпочитаю использовать приведенные выше 2 из трех его указаний для решения этой проблемы, а третий пункт дает ответ на мой вопрос LINQ (к сожалению, «НЕТ»), о котором я так или иначе не имел ни малейшего представления в качестве Всего linq n00b. - person FastAl; 31.03.2011