Где проверить аргументы метода?

Мне интересно, где и как часто - в аргументах метода проверки кода.

В приведенном ниже классе примеров (библиотека .dll), как вы думаете, лучший способ? Предположим, что я хочу проверить, что некоторый объект не может быть null (но это может быть любая другая проверка, необходимая для правильного запуска метода). Лучше ли проверять его только один раз в пункте 1., в общедоступном методе, доступном для пользователя, а позже "доверяй себе", что в других частных методах он не будет нулевым или, лучше быть немного параноидальным и проверять его каждый (в пунктах 2. 3. и 4.)

Проверка его перед использованием объекта (в пунктах 2, 3, 4) защитит меня в будущем, если я решит что-то изменить в классе, используя эти частные методы и "забудьте" передать действительный объект. Также мне не нужно помнить о проверке, если я добавлю новый публичный метод в будущем. С другой стороны, он снова и снова проверяет одно и то же условие. Или, может быть, у вас есть другие предложения?

public class MyClass()
{
    public MyClass()
    {
    }

    public void ProcessObject(SomeObject obj)
    {
        //1. if (obj == null) throw new ArgumentException("You must provide valid object.");

        DoSomething(obj);
        DoMore(obj);
        DoSomethingElse(obj);
    }

    private void DoSomething(SomeObject obj)
    {
        //2. if (obj == null) throw new ArgumenException("You must provide valid object.");
        //do something with obj...
    }

    private void DoMore(SomeObject obj)
    {
        //3. if (obj == null) throw new ArgumentException("You must provide valid object.");
        //do something with obj...
    }

    private void DoSomethingElse(SomeObject obj)
    {
        //4. if (obj == null) throw new ArgumentException("You must provide valid object.");
        //do something with obj..
    }
}  

Ответы

Ответ 1

Если это API, который вы рекламируете для других разработчиков, то на каждом из ваших методов вы действительно должны бросать либо ArgumentException, либо ArgumentNullException.

Если внутренние классы или методы, с которыми другие разработчики не будут взаимодействовать напрямую, я бы использовал Debug.Assert, поэтому в режиме отладки вы получаете дополнительную информацию об отладке, а в режиме освобождения ее отбрасывают, и вы получаете преимущество в производительности не выполнять все эти проверки аргументов всюду.

Ответ 2

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

Edit: Я бы использовал CodeContract с предварительным условием, которое проверяет, что obj не является нулевым. Поскольку это, похоже, является предварительным условием правильной работы методов.

Ответ 3

Каждый публичный метод должен проверять его ввод.

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

Однако, если у вас есть частный метод, который принимает некоторые расчетные параметры (а не те, которые передаются общедоступному методу), то необходимо выполнить дополнительную проверку.

В ваших модульных тестах будет проверяться открытый интерфейс класса, и они будут терпеть неудачу, если ваш SomeObject равен null, если ваша проверка выполняется только в ProcessObject. В этом случае я бы не дублировал проверку в частных методах.