Кажется, я попал в массивную, серьезную проблему с 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-интерфейсами, у вас есть выбор сделать это явным в коде или разрешить исключение ссылочной ссылки, чтобы помочь вам найти, где ожидания нарушены, а затем зафиксировать данные/код так или иначе.