Кажется, я попал в массивную, серьезную проблему с NullReferenceExceptions
Недавно я разрабатываю программное обеспечение, которое анализирует и отображает XML-информацию с веб-сайта. Достаточно просто?
Я получаю LOADS из NullReferenceExceptions. Например, этот метод:
private void SetUserFriends(List<Friend> list)
{
int x = 40;
int y = 3;
if (list != null)
{
foreach (Friend friend in list)
{
FriendControl control = new FriendControl();
control.ID = friend.ID;
control.URL = friend.URL;
control.SetID(friend.ID);
control.SetName(friend.Name);
control.SetImage(friend.Photo);
control.Location = new Point(x, y);
panel2.Controls.Add(control);
y = y + control.Height + 4;
}
}
}
Мне пришлось обернуть уродливый как sin Если вокруг фактического цикла foreach, чтобы предотвратить исключение.
Я чувствую, что просто помещаю бандаиды на плоскую шину вместо того, чтобы фактически решить проблему. Есть ли способ решить эту проблему? Может быть, книгу, которую я должен прочитать о шаблонах программирования, а что нет?
Действительно, я потерян. Вероятно, я задаю неправильные вопросы.
Ответы
Ответ 1
Звучит так, как будто вы не знаете, что делать, если вы получаете плохие параметры в своих методах. Там нет ничего неправильного в том, что вы делаете сейчас, но более общий шаблон - проверить параметры в голове вашего метода, выбрасывая исключение, если они не то, что вы ожидаете:
if (list == null)
{
throw new ArgumentNullException(list);
}
Это общий защитный шаблон программирования - убедитесь, что предоставленные вами данные проходят основные проверки работоспособности.
Теперь, если вы вызываете этот метод явно самостоятельно, и вы обнаруживаете, что этот метод принимает параметр null list
, когда вы этого не ожидаете, пришло время взглянуть на логику вызывающего метода. Я предпочитаю передавать пустой список, когда у меня нет элементов, а не null
, чтобы избежать особых случаев, таких как.
Ответ 2
Я, вероятно, собираюсь спуститься вниз с помощью группы "no multiple exit", но я обычно обрабатываю это с простой проверкой прямо в начале метода:
if (list == null || list.Count == 0) return;
это указывает условия выхода, и вам не нужно беспокоиться о нескольких уровнях отступов в вашем методе. Это работает только в том случае, если вы можете позволить себе усвоить тот факт, что ваш список пуст или пуст, что может случиться в некоторых случаях.
Но я согласен с codeka, поскольку вам нужно посмотреть код вызова и выработать, если вы можете улучшить его оттуда.
Ответ 3
Кажется, что защитное программирование и проверка параметров - это то, что вы ищете.
Как говорили другие, для вас будет работать простая проверка параметров:
if (list == null)
throw new ArgumentNullException("list");
В качестве альтернативы, если вы устали от постоянного написания таких проверок для каждого параметра, вы можете проверить одну из многих библиотек принудительного исполнения с открытым исходным кодом .NET. Я увлекаюсь CuttingEdge.Conditions.
Таким образом, вы можете использовать что-то вроде этого:
Condition.Requires(list, "list").IsNotNull();
Однако при настройке предварительного условия, как и в приведенном выше, будет просто указано, что ваш метод не принимает значения null. Ваша проблема будет по-прежнему существовать в том, что вы передаете null в метод! Чтобы исправить это, вам нужно будет изучить, что вызывает ваши методы, и выяснить, почему передаются пустые объекты.
Ответ 4
Также, как и для исключения исключений ArgumentNullException, есть также что-то, называемое "Null Obejct Pattern", которое вы можете использовать, если хотите, чтобы оно проходило вокруг нуля, чтобы указать, например, что что-то не существует, но не хотите явно проверить наличие нулей. По сути, это класс-заглушка, который реализует один и тот же интерфейс, но его методы обычно либо пусты, либо возвращаются достаточно, чтобы сделать их завершенными.
http://en.wikipedia.org/wiki/Null_Object_pattern
Также полезно для типов значений, которые не могут легко выразить их не существование, не будучи в состоянии быть нулевым.
Ответ 5
Я вернусь раньше (или рано запускаю InvalidArgumentException), когда вы получите недопустимый ввод.
Например:
private void SetUserFriends(List<Friend> list)
{
if (list == null)
return;
/* Do stuff */
}
В качестве альтернативы вы можете использовать общий шаблон нулевой коалесценции:
private void SetUserFriends(List<Friend> list)
{
list = list ?? new List<Friend>();
/* Do Stuff */
}
Ответ 6
Вы действительно задаете неправильный вопрос. Правильный вопрос: "null означает недопустимый ввод или флаг, который означает X".
До тех пор, пока не будут добавлены ненулевые ссылочные типы к языку и сделайте свой путь различными API-интерфейсами, у вас есть выбор сделать это явным в коде или разрешить исключение ссылочной ссылки, чтобы помочь вам найти, где ожидания нарушены, а затем зафиксировать данные/код так или иначе.