предотвращение исключений нулевой ссылки

По-видимому, подавляющее большинство ошибок в коде является исключениями нулевой ссылки. Там какие-либо общие методы состоят в том, чтобы не встречаться с ошибками нулевой ссылки?

Если я не ошибаюсь, я знаю, что на языках, таких как F# это не возможный иметь нулевое значение. Но это не вопрос, я спрашиваю, как избежать ошибок нулевой ссылки на языках, таких как C#.

22
задан Nippysaurus 22 December 2009 в 00:17
поделиться

11 ответов

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

Мои лучшие рекомендации для людей, которые заботятся о качестве программного обеспечения, и также используют платформу программирования программирования .Net, это установить и использовать контракты Microsoft Code ( http://msdn.microsoft.com/en-us/ devlabs / dd491992.aspx ). Он включает в себя возможности для проверки выполнения и статической проверки. Основные возможности создания этих контрактов в ваш код включены в версию 4.0 Framework. Если вы заинтересованы в качестве кода, и он звучит так, как вы, возможно, вам действительно может понравиться использовать контракты Microsoft Code.

С кодами Microsoft Code Contons вы можете охранять ваш метод от нулевых значений, добавив предпосылки, такие как этот «Contract.requires (Customer! = NULL);». Добавление того, как это, как это, эквивалентно практике, рекомендованной многими другими в своих комментариях выше. Перед кодом контрактов я бы рекомендовал вам сделать что-то вроде этого

if (customer == null) {throw new ArgumentNullException("customer");}

теперь, я рекомендую

Contract.Requires(customer != null);

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

Исследование распространенности нулевых справочных ошибок

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

  • Ведущие исследователи Microsoft в Программа правильности на спецификации # и Кодовые договоры проекты считают, что это проблема стоит обращение к решению.
  • ДР. Бертран Мейер и команда инженеры программного обеспечения в ISE, кто Разработано и поддерживает Эйфелеву Язык программирования, также верю в это это проблема, на которую стоит обращаться.
  • В моем собственном коммерческом опыте разработку обычного программного обеспечения, я видел нулевые ссылочные ошибки достаточно часто, что я хотел бы решить проблему в своих собственных продуктах и ​​практиках.

В течение многих лет Microsoft инвестировала в исследования, предназначенные для улучшения качества программного обеспечения. Одним из их усилий был проект SPEC #. Одним из самых захватывающих событий, на мой взгляд с Framework The.NET 4.0, является введение контрактов Microsoft Code, что является наростом более ранней работы, проделанной командой SPECT # TV.

Что касается вашего замечания «Подавляющее большинство ошибок в коде, являются нулевыми контрольными исключениями», я считаю, что это квалификатор «Подавляющее большинство», которое приведет к некоторым разногласиям. Фраза «подавляющее большинство» предполагает, что, возможно, 70-90% неисправностей имеют нулевой контроль исключения в качестве корневой причины. Это кажется слишком высоко для меня. Я предпочитаю цитировать из исследования Microsoft SPEC #. В своей статье система программирования SPEC #: обзор, Майк Барнетт, К. Рустан М. Лейно и Вольфрам Шулте. В CASSIS 2004, LNCS Vol. 3362, Springer, 2004, они писали

1.0 ненулевых типов. Многие ошибки в современных программах проявляются как Ошибки null-dereence, предполагающие Важность программирования язык, обеспечивающий способность различать выражения, которые может оценить нулевые и те, что уверены не (для некоторых экспериментальных Доказательства, см. [24, 22]). На самом деле, мы хотел бы искоренить все нулевые Ошибки неэлеверсов.

Это вероятный источник для людей в Microsoft, которые знакомы с этим исследованием. Эта статья доступна на сайте SPEC #.

Я скопировал ссылки 22 и 24 ниже,и включал ISBN для вашего удобства.

  • Мануэль Фахндрих и К. Рустан М. Лейно. Объявление и проверка ненулевых типов в Объектно-ориентированный язык. В процессе конференции ACM 2003 года на объектно-ориентированном Программирование, системы, языки и приложения, OOPLA 2003, том 38, номер 11 в Sigplan уведомлен, страницы 302-312. ACM, ноябрь 2003 года. ISBN = {1-58113-712-5},

  • Cormac Flanagan, К. Рустан М. Лейно, Марк Лилибридж, Грег Нельсон, Джеймс Б. Сакс, И Рэйми Статина. Расширенная статическая проверка для Java. В разбирательстве 2002 года ACM Sigplan Конференция по проектированию и реализации языка программирования (PLDI), объем 37, номер 5 в Sigplan Уведомления, стр. 234-245. ACM, май 2002 г.

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

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

Я также помню, как кое-что о том, что в объявлении ISE на недавнем выпуске Эйфелева. Они обращаются к этому вопросу как «недействительную безопасность», и, как и многие вещи, вдохновленные или разработанные доктором Бертром Мейером, у них есть красноречивая и образовательная описание проблемы и как они ходят, предотвращают его на их языке и инструменты. Я рекомендую вам прочитать свою статью http://doc.eiffel.com/book/method/void-safety-background-definition-and-dools , чтобы узнать больше.

Если вы хотите узнать больше о Контрактах Microsoft Code, недавно возникли тонны статей. Вы также можете проверить свой блог на http: Slash Slash CodeContracts.info, который в первую очередь посвящен разговорам о качестве программного обеспечения благодаря использованию программирования с договорами.

30
ответ дан 29 November 2019 в 03:26
поделиться

Вы можете легко проверить, нет ли нулевой ссылки, прежде чем она вызовет исключение, но обычно это не является реальной проблемой, так что в конце концов вы все равно выбросите исключение, так как код на самом деле не может продолжать работу без каких-либо данных.

Часто основная проблема не в том, что у вас есть нулевая ссылка, а в том, что вы получили нулевую ссылку в первую очередь. Если ссылка не должна быть нулевой, то вы не должны проходить точку, в которой инициализируется ссылка, не имея правильной ссылки.

5
ответ дан 29 November 2019 в 03:26
поделиться

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

.
4
ответ дан 29 November 2019 в 03:26
поделиться

Использование Null Object Patterns является ключевым моментом.

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

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

.
5
ответ дан 29 November 2019 в 03:26
поделиться

Нет.

Вернее, нет ничего особенного в том, чтобы попытаться "предотвратить" NRE на C#. По большей части NRE - это просто какая-то логическая ошибка. Вы можете отгородиться от них на границах интерфейса, проверяя параметры и имея много кода типа

void Foo(Something x) {
    if (x==null)
        throw new ArgumentNullException("x");
    ...
}

повсюду (большая часть .Net Framework делает это), так что когда вы делаете ошибку, вы получаете немного более информативную диагностику (трасса стека, однако, еще более ценна, и NRE обеспечивает это тоже). Но вы все равно получаете исключение.

(Исключение: Такие исключения - NullReferenceException, ArgumentNullException, ArgumentException, ... - как правило, не должны попадаться программе, а просто означают "разработчик этого кода, есть ошибка, пожалуйста, исправьте ее". Я называю их исключениями 'время разработки'; они контрастируют с истинными исключениями 'время выполнения', которые происходят в результате окружения времени выполнения (например, FileNotFound) и предназначены для того, чтобы потенциально быть пойманными и обработанными программой. )

Но в конце концов, нужно просто правильно это закодировать.

В идеале большинство NRE никогда бы не случилось, так как для многих типов/переменных 'null' является бессмысленным значением, а в идеале статическая система типов запретила бы 'null' в качестве значения для этих конкретных типов/переменных. Тогда компилятор не позволил бы ввести этот тип случайной ошибки (исключая определенные классы ошибок, которые лучше всего подходят компиляторам и системам типов). В этом случае определенные языки и системы типов преуспевают.

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

.
7
ответ дан 29 November 2019 в 03:26
поделиться

В дополнение к вышесказанному ("Нулевые объекты", "Пустые коллекции"), существуют некоторые общие техники, а именно: Приобретение ресурсов - инициализация (RAII) с С++ и проектирование по контракту с компанией "Эйфель". Они сводятся к:

  1. Инициализировать переменные с действительными значениями.
  2. Если переменная может быть нулевой, то либо проверьте ее на наличие нуля и рассмотрите как особый случай, либо ожидайте исключение с нулевой ссылкой (и разберитесь с этим). Утверждения могут быть использованы для проверки на нарушение договора при разработке.

Я видел много кода, который выглядит так:

if ((value != null) && (value.getProperty() != null) && ... && (....). doSomethingUseful())

Большую часть времени это совершенно ненужно и большинство тестов можно убрать более строгой инициализацией и более жесткими определениями контрактов.

Если это проблема в вашей кодовой базе, то в каждом случае необходимо понимать, что представляет собой ноль:

  1. Если ноль представляет пустую коллекцию, то используйте пустую коллекцию.
  2. Если ноль представляет собой исключительный случай, бросьте Исключение.
  3. Если ноль представляет случайно неинициализированную ценность, явно инициализируйте его.
  4. Если ноль представляет собой законную ценность, протестируйте его - или даже лучше используйте NullObject, который выполняет нулевую операцию

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

.
21
ответ дан 29 November 2019 в 03:26
поделиться

Здесь могут помочь хорошие инструменты анализа кода. Хорошие юнит-тесты также могут помочь, если вы используете инструменты, которые рассматривают ноль как возможный путь через ваш код. Попробуйте бросить этот переключатель в настройки сборки, который говорит "относиться к предупреждениям как к ошибкам" и посмотрите, можете ли вы оставить # предупреждений в вашем проекте = 0. Возможно, вы обнаружите, что предупреждения говорят много.

Следует помнить, что это может быть good вещь, которую вы бросаете нулевое - ссылочное исключение. Почему? Потому что это может означать, что код, который должен был не выполнялся. Инициализация к значениям по умолчанию - хорошая идея, но вы должны быть осторожны, чтобы не скрыть проблему.

List<Client> GetAllClients()
{
    List<Client> returnList = new List<Client>;
    /* insert code to go to data base and get some data reader named rdr */
   for (rdr.Read()
   {
      /* code to build Client objects and add to list */
   }

   return returnList;
}

Хорошо, это может выглядеть нормально, но в зависимости от ваших бизнес-правил, это может быть проблемой. Конечно, вы никогда не бросите нулевую ссылку, но, может быть, ваша таблица User никогда не должна быть пустой? Вы хотите, чтобы ваше приложение вращалось на месте, генерируя вызовы поддержки от пользователей, говорящих "это просто пустой экран", или вы хотите поднять исключение, которое может где-нибудь войти в журнал и быстро поднять тревогу? Не забудьте проверить, что вы делаете, а также "обработка" исключений. Это одна из причин, по которой некоторые не любят убирать нули из наших языков... это облегчает поиск ошибок, даже если это может привести к появлению новых.

Помните: Обращайтесь с исключениями, не скрывайте их.

2
ответ дан 29 November 2019 в 03:26
поделиться

Одним из простейших способов избежать NullReferenceExceptions является агрессивная проверка нулевых ссылок в конструкторах/методах/свойствах вашего класса и привлечение внимания к проблеме.

Например

public MyClass
{
   private ISomeDependency m_dependencyThatWillBeUsedMuchLater 

   // passing a null ref here will cause 
   // an exception with a meaningful stack trace    
   public MyClass(ISomeDependency dependency)
   {
      if(dependency == null) throw new ArgumentNullException("dependency");

      m_dependencyThatWillBeUsedMuchLater = dependency;
   }

   // Used later by some other code, resulting in a NullRef
   public ISomeDependency Dep { get; private set; }
}

В приведенном выше коде, если вы передадите нулевое ref, то сразу же обнаружите, что код вызова использует тип некорректно. Если не было проверки нулевой ссылки, то ошибка может быть затушевана самыми разными способами.

Вы заметите, что библиотеки .NET-фреймворка почти всегда терпят неудачу раньше и часто, если вы предоставляете нулевые ссылки в тех случаях, когда это не корректно. Так как брошенное исключение явно говорит "ты облажался!" и объясняет почему, это делает обнаружение и исправление дефектного кода тривиальной задачей.

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

Что бы вы предпочли, ArgumentNullException на входном методе, или непонятную ошибку в его кишках? Чем дальше от источника ошибки, тем труднее ее отследить.

2
ответ дан 29 November 2019 в 03:26
поделиться

Одна из наиболее распространенных ошибок нулевой ссылки, которую я видел, связана со строками. Будет проверка:

if(stringValue == "") {}

Но на самом деле строка нулевая. Так и должно быть:

if(string.IsNullOrEmpty(stringValue){}

Также, можно быть чересчур осторожным и проверять, что объект не является нулевым, прежде чем пытаться получить доступ к членам/методам этого объекта.

.
4
ответ дан 29 November 2019 в 03:26
поделиться

Соответствующее использование структурированной обработки исключений поможет избежать подобных ошибок.

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

.
2
ответ дан 29 November 2019 в 03:26
поделиться

Один из способов - использовать объекты Null Value Objects (также известные как Null Object Pattern) там, где это возможно. Здесь подробнее

3
ответ дан 29 November 2019 в 03:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: