нулевые объекты против пустых объектов

вы можете программно установить число столбцов, используя

float scalefactor = getResources().getDisplayMetrics().density * 100;
int number = getWindowManager().getDefaultDisplay().getWidth();
int columns = (int) ((float) number / (float) scalefactor);
gridView.setNumColumns(columns);
13
задан Community 23 May 2017 в 11:46
поделиться

10 ответов

I tend to be dubious of code with lots of NULLs, and try to refactor them away where possible with exceptions, empty collections, and so on.

The "Introduce Null Object" pattern in Martin Fowler's Refactoring (page 260) may also be helpful. A Null Object responds to all the methods a real object would, but in a way that "does the right thing". So rather than always check an Order to see if order.getDiscountPolicy() is NULL, make sure the Order has a NullDiscountPolicy in these cases. This streamlines the control logic.

7
ответ дан 1 December 2019 в 17:51
поделиться

Нулевой получает мой голос. Опять же, я придерживаюсь мышления «безотказно».

String.IsNullOrEmpty (...) тоже очень полезен, я думаю, он улавливает любую ситуацию: пустые или пустые строки. Вы можете написать аналогичную функцию для всех ваших классов.

4
ответ дан 1 December 2019 в 17:51
поделиться

Передача ненулевого значения только для того, чтобы избежать исключения NullReferenceException, меняет прямую, легко решаемую проблему («она взрывается, потому что она равна нулю») на гораздо более тонкую и трудноразрешимую проблему. проблема отладки («что-то несколько вызовов вниз по стеку ведет себя не так, как ожидалось, потому что гораздо раньше оно получило какой-то объект, который не имеет значимой информации, но не равен нулю»).

NullReferenceException - замечательная вещь ! Он выходит из строя резко, громко, быстро, и его почти всегда быстро и легко определить и исправить. Это мое любимое исключение, потому что я знаю, что когда увижу его, моя задача займет около 2 минут. Сравните это с запутанным QA или отчетом клиента, пытающимся описать странное поведение, которое должно быть воспроизведено и прослежено до источника. Уф.

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

Соблюдение подобной практики кодирования в каждой точке "шлюза" - логические границы функциональности в вашем коде - исключения NullReferenceExceptions должны быть гораздо более редкими.

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

Соблюдение подобной практики кодирования в каждой точке «шлюза» - логические границы функциональности в вашем коде - исключения NullReferenceExceptions должны быть гораздо более редкими.

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

Соблюдение подобной практики кодирования в каждой точке «шлюза» - логические границы функциональности в вашем коде - исключения NullReferenceExceptions должны быть гораздо более редкими.

26
ответ дан 1 December 2019 в 17:51
поделиться

Особенность null в том, что он не имеет смысла. Это просто отсутствие объекта.

Итак, если вы действительно имеете в виду пустую строку / коллекцию / что угодно, всегда возвращайте соответствующий объект и никогда null . Если рассматриваемый язык позволяет вам указать это, сделайте это.

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

2
ответ дан 1 December 2019 в 17:51
поделиться

Если вы пишете код, который возвращает null в качестве условия ошибки, то не делайте этого: как правило, вместо этого следует генерировать исключение - гораздо труднее пропустить.

Если вы используете код, который, как вы опасаетесь, может вернуть значение null, то в основном это тупые исключения : возможно, сделайте некоторые Debug.Assert у вызывающей стороны, чтобы проверить вывод во время разработки . Вам не следует действительно нуждаться в огромных числах null проверок в вашем производстве, но если какая-то сторонняя библиотека возвращает много null s непредсказуемо, тогда обязательно: сделайте проверки.

В 4.0 вы, возможно, захотите посмотреть на код-контракты; это дает вам гораздо лучший контроль, чтобы сказать «этот аргумент никогда не должен передаваться как null», »

3
ответ дан 1 December 2019 в 17:51
поделиться

Вы не можете всегда возвращать пустой объект, потому что «пустой» не всегда определяется. Например, что означает, что int, float или bool должны быть пустыми?

Возврат указателя NULL не обязательно является плохой практикой, но я думаю, что лучше всего вернуть ссылку (const) (где это имеет смысл для этого, конечно).

И в последнее время я часто использую класс Fallible:

Fallible<std::string> theName = obj.getName();
if (theName)
{
    // ...
}

Для такого класса доступны различные реализации (проверьте Google Code Search), Я также создал свой собственный .

0
ответ дан 1 December 2019 в 17:51
поделиться

For the exception protagonists they usually stem from transactional programming and strong exception safety guarantees or blind guidelines. In any decent complexity, ie. async workflow, I/O and especially networking code they are simply inappropriate. The reason why you see Google style docs on the matter in C++, as well as all good async code 'not enforcing it' (think your favourite managed pools as well).

There is more to it and while it might look like a simplification, it really is that simple. For one you will get a lot of exceptions in something that wasn't designed for heavy exception use.. anyway I digress, read upon on this from the world's top library designers, the usual place is boost (just don't mix it up with the other camp in boost that loves exceptions, because they had to write music software :-).

In your instance, and this is not Fowler's expertise, an efficient 'empty object' idiom is only possible in C++ due to available casting mechanism (perhaps but certainly not always by means of dominance ).. On ther other hand, in your null type you are capable throwing exceptions and doing whatever you want while preserving the clean call site and structure of code.

In C# your choice can be a single instance of a type that is either good or malformed; as such it is capable of throwing acceptions or simply running as is. So it might or might not violate other contracts ( up to you what you think is better depending on the quality of code you're facing ).

In the end, it does clean up call sites, but don't forget you will face a clash with many libraries (and especially returns from containers/Dictionaries, end iterators spring to mind, and any other 'interfacing' code to the outside world ). Plus null-as-value checks are extremely optimised pieces of machine code, something to keep in mind but I will agree any day wild pointer usage without understanding constness, references and more is going to lead to different kind of mutability, aliasing and perf problems.

To add, there is no silver bullet, and crashing on null reference or using a null reference in managed space, or throwing and not handling an exception is an identical problem, despite what managed and exception world will try to sell you. Any decent environment offers a protection from those (heck you can install any filter on any OS you want, what else do you think VMs do), and there are so many other attack vectors that this one has been overhammered to pieces. Enter x86 verification from Google yet again, their own way of doing much faster and better 'IL', 'dynamic' friendly code etc..

Go with your instinct on this, weight the pros and cons and localise the effects.. in the future your compiler will optimise all that checking anyway, and far more efficiently than any runtime or compile-time human method (but not as easily for cross-module interaction).

1
ответ дан 1 December 2019 в 17:51
поделиться

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

1
ответ дан 1 December 2019 в 17:51
поделиться

How are empty objects better than null objects? You're just renaming the symptom. The problem is that the contracts for your functions are too loosely defined "this function might return something useful, or it might return a dummy value" (where the dummy value might be null, an "empty object", or a magic constant like -1. But no matter how you express this dummy value, callers still have to check for it before they use the return value.

If you want to clean up your code, the solution should be to narrow down the function so that it doesn't return a dummy value in the first place.

If you have a function which might return a value, or might return nothing, then pointers are a common (and valid) way to express this. But often, your code can be refactored so that this uncertainty is removed. If you can guarantee that a function returns something meaningful, then callers can rely on it returning something meaningful, and then they don't have to check the return value.

0
ответ дан 1 December 2019 в 17:51
поделиться

Если вы серьезно относитесь к программированию в среде " null less" рассмотрите возможность использования методов расширения чаще, они невосприимчивы к исключениям NullReferenceExceptions и, по крайней мере, «притвориться», что null больше не существует:

public static GetExtension(this string s)
{
    return (new FileInfo(s ?? "")).Extension;
}

который можно назвать так:

// this code will never throw, not even when somePath becomes null
string somePath = GetDataFromElseWhereCanBeNull();
textBoxExtension.Text = somePath.GetExtension(); 

Я знаю, это всего лишь удобство, и многие люди правильно считают это нарушением ОО-принципов (хотя «основатель» ОО, Бертран Мейер, считает нулевым злом и полностью изгнал его из его объектно-ориентированного дизайна, который применяется к языку Eiffel, но это уже другая история). РЕДАКТИРОВАТЬ: Дэн упоминает, что Билл Вагнер ( Более эффективный C # ) считает это плохой практикой, и он прав. Вы когда-нибудь задумывались о методе расширения IsNull ;-)?

Чтобы сделать ваш код более читабельным, может быть использован другой совет: чаще используйте оператор объединения с нулевым значением, чтобы указать значение по умолчанию, когда объект имеет значение NULL :

// load settings
WriteSettings(currentUser.Settings ?? new Settings());

// example of some readonly property
public string DisplayName
{
    get 
    {
         return (currentUser ?? User.Guest).DisplayName
    }
}

Ни один из них не выполняет периодическую проверку на null ?? - не более чем скрытая ветвь if). Я предпочитаю как можно меньше null в моем коде просто потому, что считаю, что это делает код более читабельным. Когда мой код загроможден операторами if для null , я знаю, что что-то не так с дизайном, и выполняю рефакторинг. Я предлагаю любому сделать то же самое, но я знаю, что мнения по этому поводу сильно разнятся.

(Обновление) Сравнение с исключениями

Пока в обсуждении не упоминается сходство с обработкой исключений. Когда вы обнаруживаете, что повсеместно игнорируете null всякий раз, когда считаете, что это мешает вам, это в основном то же самое, что писать:

try 
{
    //...code here...
}
catch (Exception) {}

, который имеет эффект удаления любых следов исключений только для того, чтобы обнаружить, что это вызывает несвязанные исключения намного позже в коде. Хотя я считаю полезным избегать использования null , как упоминалось ранее в этом потоке, наличие null для исключительных случаев - это хорошо. Только не скрывайте их в блоках с нулевым игнорированием, это будет иметь тот же эффект, что и блоки перехвата всех исключений.

Хотя я считаю полезным избегать использования null , как упоминалось ранее в этом потоке, наличие null для исключительных случаев - это хорошо. Только не скрывайте их в блоках с нулевым игнорированием, это будет иметь тот же эффект, что и блоки перехвата всех исключений.

Хотя я считаю полезным избегать использования null , как упоминалось ранее в этом потоке, наличие null для исключительных случаев - это хорошо. Только не прячьте их в блоках с нулевым игнорированием, это будет иметь тот же эффект, что и блоки перехвата всех исключений.

1
ответ дан 1 December 2019 в 17:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: