Ожидаемое поведение, когда запрос на коллекцию будет иметь нулевые элементы

13

Допустим, вам дано следующее ...

List<Thing> theThings = fubar.Things.All();

Если бы нечего было возвращать, чего бы вы ожидали от fubar.Things.All ()?

Редактировать: Спасибо за мнения. Я подожду немного и приму запись с наибольшим количеством взлетов.

Я согласен с ответами, особенно теми, которые предлагают пустую коллекцию. Поставщик предоставил API с несколькими вызовами, аналогичными приведенному выше примеру. Вендор, который в прошлом году заработал 4,6 млн. Долл. США через свои API, BTW. Они делают то, с чем я принципиально не согласен - они бросают исключение.

abscode
источник
Кажется, довольно солидный консенсус [здесь] [1]: Пустая коллекция. Всегда. [1]: stackoverflow.com/questions/1969993/…
Джесси С. Слайсер
Для чего нужен тип данных Things? Если имеет смысл иметь Thingsполе, возвращающее нуль, то имеет смысл получить исключение, потому что вы не проверяли ноль перед вызовом All(). Однако я согласен с людьми, которые думают, что fubar.Thingsследует возвращать пустую коллекцию вместо нуля.
Колин Д.
Я вижу, к чему ты клонишь, Колин. В этом случае вы можете предположить, что Вещи существуют, и All () является статическим. Исключением является пустая коллекция, а не какая-либо другая причина.
abscode
О боже, они бросают исключение ...! o_O
Стюарт Маркс
Теперь, более интересным вопросом было бы то, какую причину на Земле мог бы бросить каждый в таком родовом случае, или что делает случай настолько особенным, чтобы оправдать Бросок ??!
Мартин Ба

Ответы:

29

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

List<Thing> theThings = fubar.Things.All();
if (theThings != null) {
    for (Thing t : theThings) {
        t.doSomething();
    }
}

они смогут написать это:

List<Thing> theThings = fubar.Things.All();
for (Thing t : theThings) {
    t.doSomething();
}

Этот второй фрагмент кода короче и его легче читать, потому что уровень вложенности ниже на единицу.

dasblinkenlight
источник
2
Я думаю, что мне также было бы легче понять концептуально, как «набор пуст» (без элементов). Нуль - это «нет множества», что совсем другое. (Это также должно охватывать вещи, которые являются логически невозможными - набор всех нечетных элементов, которые также являются четными, должен быть пустым, а не нулевым). Я, честно говоря, не уверен, что (по логике) будет представлять собой нулевое множество ... (даже если вы голый на острове, ваше имущество пустое, а не нулевое)
Clockwork-Muse
@ X-Zero Но если вы обнажены, «вещи в рюкзаке» могут вернуть ноль, так как у вас даже нет рюкзака. Это может быть BackpackNotFoundException, но только если это действительно неожиданно. Это должно быть нормальное состояние, скажем, в игре на выживание на острове.
Изката
Дополнительная нулевая проверка - это то, что помогает мне спать по ночам.
Джоэл Б
6

Я ожидал бы пустой список. theThingsвсе равно будет объектом, но theThings.Countили theThings.size()вернется 0.

Дэвид Хог
источник
5

Подобные проблемы проектирования решаются с помощью шаблона Null Object.

... Вместо использования нулевой ссылки для передачи отсутствия объекта (например, несуществующего клиента), используется объект, который реализует ожидаемый интерфейс, но тело метода которого пусто. Преимущество этого подхода перед рабочей реализацией по умолчанию состоит в том, что Null Object очень предсказуем и не имеет побочных эффектов: он ничего не делает.

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

Предложение особенно применимо в вашем случае (возвращение, Listкогда нет Things):

... Возвращая пустой объект (т. Е. Пустой список ), нет необходимости проверять, что возвращаемое значение на самом деле является списком. Вызывающая функция может просто перебирать список как обычно, фактически ничего не делая. Однако все еще можно проверить, является ли возвращаемое значение нулевым объектом (например, пустым списком), и при желании реагировать по-разному.

комар
источник
3

ИМХО, вы должны вернуть ПУСТОЕ значение. Я не знаю о C #, но в Java у нас есть это:

  List list = Collections.EMPTY_LIST;
  Set set = Collections.EMPTY_SET;
  Map map = Collections.EMPTY_MAP;

  // For the type-safe 
  List<String> s = Collections.emptyList();
  Set<Long> l = Collections.emptySet();
  Map<Date> d = Collections.emptyMap();

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html

Марсело Ассис
источник
1
Эквивалент C # Enumerable.Empty<T>(), который возвращает пустой IEnumerable<T>(см. Msdn.microsoft.com/en-us/library/bb341042.aspx )
Авнер Шахар-Каштан
1
Текущие документы здесь: docs.oracle.com/javase/7/docs/api/java/util/Collections.html - документам 1.4.2 уже около десяти лет.
Стюарт Маркс
2

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


источник
2

Два решения они означают разные вещи.

Если есть только ноль того, что вы возвращаете, вы ВСЕГДА возвращаете пустую коллекцию! Возьмите случай со списком каталогов. Если в каталоге нет файлов, вы возвращаете пустую коллекцию файлов.

С другой стороны, если каталог не существует, это не совсем подходит. «Я ничего не могу вернуть» означает нечто совершенно иное. В этом случае вы должны либо возвратить ноль, либо выдать исключение в зависимости от ситуации, а не просто вернуть пустую коллекцию, как будто ничего не случилось.

Билл К
источник
Очень разумное объяснение. Возвращенный результат не должен покрывать недопустимое состояние, у нас есть исключения для этого.
Ивайло Славов