Null – не то же самое, что Empty

Когда я начал этот блог в 2003 году, один из первых постингов был про отличия между Null, Empty и Nothing в VBScript. Цитата:

Предположим, у вас есть база данных с отчетами о продажах, и вы спрашиваете её: «какова сумма всех продаж в августе?» Но один из менеджеров еще не отправил свой отчёт об августовских продажах. Каков корректный ответ? Вы можете спроектировать базу так, чтобы она игнорировала отсутствие данных и возвращала сумму известных продаж, но это ответит на другой вопрос. Вопрос был не «какова сумма всех известных продаж в августе, исключая отсутствующие данные?». Вопрос был «какова сумма всех продаж в августе?» Ответ на тот вопрос – «я не знаю – тут данных не хватает», так что база возвращает Null.

Этот принцип лежит в основе дизайна Nullable типов-значений в C#. Причина, по которой мы вообще имеем Nullable типы в том, что существует семантическая разница между null integer/decimal/double/кемугодно и нулями этих типов. Нуль означает «я знаю, что количество равно нулю», а null означает «я не знаю, чему равно количество».

Это также объясняет, почему null-ы распространяются; если вы сложите два nullable int-а и один из них null, то результат тоже null. Ясно, что десять плюс «я не знаю» равно «я не знаю», а не десять.

Концепция «null это отсутствие информации» также применима к ссылочным типам, которые, конечно же, всегда nullable. Меня иногда спрашивают, почему C# не трактует null, переданный в «foreach» просто как пустую коллекцию, или не считает null integer-ы нулями. Есть семантическая разница между «известно, что коллекция результатов пуста» и «коллекцию результатов даже не удалось получить», и мы хотим позволить вам сохранять это различие, а не размыть границу между ними. Трактуя null как «пусто», мы бы уменьшили ценность возможности четко отличать отсутствующую или некорректную коллекцию от наличествующей, корректной, пустой коллекции.

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

foreach(Customer customer in customers ?? Enumerable.Empty<Customer>())

Оператор ?? означает «используй левый аргумент, но если он null, то используй правый аргумент». Типа, удобно.

оригинал статьи