Подтвердить что ты не робот

Никогда не используйте Nulls?

В настоящее время мы продолжаем длительный процесс написания некоторых стандартов кодирования для С#.

Недавно я написал метод с сигнатурой

string GetUserSessionID(int UserID)

GetUserSession() возвращает null в случае, если сеанс не найден для пользователя.

в моем кодовом коде... Я говорю...

string sessionID = GetUserSessionID(1)
if (null == sessionID && userIsAllowedToGetSession)
{
    session = GetNewUserSession(1);
}

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

Сразу же я закричал, как будто вы вернули строку. Возможно, вам еще нужно выполнить какую-то проверку на возвращаемое значение.

if (string.Empty == sessionID)

Однако, подумав об этом, я никогда не верну null в случае коллекции/массива/списка. Я бы вернул пустой список.

Решение этой проблемы (я думаю) должно было бы реорганизовать это на 2 метода.

bool SessionExists(int userID);

и

string GetUserSessionID(int UserID);

На этот раз GetUserSessionID будет генерировать исключение SessionNotFound (так как он не должен возвращать null)

теперь код будет выглядеть как...

if(!SessionExists(1) && userIsAllowedToGetSession))
{
   session = GetNewUserSession(1);
}
else
{
   session = GetUserSessionID(1);
}

Теперь это означает, что нет нулей, но для меня это кажется немного более сложным. Это также очень простой пример, и мне было интересно, как это повлияет на более сложные методы.

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

Есть ли у кого-нибудь еще какие-либо твердые рекомендации (или даже более высокие стандарты) относительно использования нулей и что это означает для типов с нулевым значением (мы вообще должны их использовать?)

Спасибо заранее,

Крис.

=====

Спасибо всем! Здесь много интересного.

Я дал ответ эгаге, поскольку мне нравится предложение Get vs Find в качестве руководства по кодированию, но все были интересными ответами.

4b9b3361

Ответ 1

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

Конечно, следует избегать нулей, и Андрей Хельсберг сказал в интервью, что если бы С# был создан сейчас, у него были бы более эффективные способы борьбы с недействительностью. http://www.computerworld.com.au/article/261958/-z_programming_languages_c?pp=3&fp=&fpid=

Ответ 2

нули определенно лучше, то есть более честны, чем "магические значения". Но они не должны возвращаться, когда произошла ошибка - что за исключения сделаны. Когда дело доходит до возвращения коллекций... лучше пустую коллекцию, чем null, я согласен.

Ответ 3

возвращает значение null в порядке, и следующее краткое и понятное:

var session = GetUserSessionID(1) ?? GetNewUserSession(1);

Ответ 4

По-моему, вы не должны исключать использование null в качестве возвращаемого значения. Я думаю, что это действительно во многих случаях. Но вы должны тщательно рассмотреть pro и con для каждого метода. Это полностью зависит от цели метода и ожиданий, которые могут возникнуть у вызывающих.

Я лично часто использую значение возвращаемого значения null в тех случаях, когда вы можете ожидать, что метод не возвращает abject (т.е. поиск базы данных с помощью первичного ключа, может возвращать ровно один экземпляр или none/null). Когда вы можете правильно ожидать, что метод вернет значение, вы должны использовать исключение.

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

Ответ 6

Держите вещи Простыми. Сделайте его настолько безболезненным, насколько это возможно для потребителя вашего типа. Это компромисс: время для реализации и выгоды.

  • Когда вы занимаетесь такими вещами, как выборка списков/коллекций, верните пустой список, как вы правильно указали.
  • Аналогично для случаев, когда вам нужно вернуть значение "null", чтобы обозначить "не найденный" - попробуйте использовать шаблон Null Object для сильно используемого типа. Для редко используемых типов, я думаю, вы могли бы жить с несколькими проверками на null или -1 (String.IndexOf).

Если у вас есть больше категорий, отправьте в виде комментариев и я попытаюсь решить проблемы.

Ответ 7

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

bool TryGetUserSession(int sessionId, out session)

Также попробуйте не писать nulls ==???, поскольку некоторым разработчикам сложнее читать.

С уважением,

Ответ 8

Я опасаюсь возвращать нули сам, хотя в вашем примере это, безусловно, кажется правильным.

Важно то, что clear имеет значение nullability как для аргументов, так и для возвращаемых значений. Это должно быть указано как часть вашей документации API, если ваш язык не может выразить эту концепцию напрямую. (Java не может, я читал, что С# может.) Если входной параметр или возвращаемое значение может быть нулевым, обязательно сообщите пользователям, что это означает в контексте вашего API.

Наша самая большая база кода - это Java-приложение, которое неуклонно растет за последнее десятилетие. Многие из внутренних API очень неясны в отношении их поведения WRT null. Это приводит к злокачественному росту нулевых проверок повсюду, потому что все программируют в обороне.

Особенно уродливые: функции, возвращающие коллекции, возвращающие null вместо пустой коллекции. WTF!? Не делай этого!

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

Одна часть системы, которая предоставляет запросы к структурам, подобным XML, для реализации бизнес-правил, очень радикальна в отношении того, что она является нулевой. Он использует шаблон Null Object повсеместно. В этом контексте это оказывается полезным, потому что оно позволяет вам делать такие вещи, как:

A.children().first().matches("Blah")

Идея состоит в том, что это выражение должно возвращать true, если первый дочерний элемент A называется "Blah". Он не будет разбиваться, если у A нет дочерних элементов, потому что в этом случае first() возвращает NullNode, который реализует интерфейс Node, но никогда не "соответствует" чему-либо.

Вкратце:

  • Проясните значение и допустимость null в ваших API.
  • Используйте свой мозг.
  • Не будьте догматичны.

Ответ 9

Одним из решений может быть объявление простого типа возврата для таких вещей:

class Session
{
    public bool   Exists;
    public string ID;
}

Session GetUserSession(int userID) {...}

...

Session session = GetUserSessionID(1);

if (session.Exists)
{
    ... use session.ID
}

Мне обычно нравится избегать нулей, но строки - это особый случай. Я часто вызываю string.IsNullOrEmpty(). Настолько, что мы используем метод расширения для строки:

static class StringExtensions
{
    public static bool IsNullOrEmpty(this string value)
    {
        return string.IsNullOrEmpty(value);
    }
}

Затем вы можете сделать:

string s = ... something

if (s.IsNullOrEmpty())
{
 ...
}

Кроме того, поскольку мы обсуждаем стиль кодирования:

Что с неестественно выглядящим "if (null ==...)" стилем? Это совершенно не важно для С# - похоже, что кто-то привел в С# -кодирование С++-код!

Ответ 10

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

if( list != null) {
    foreach( Item item in list ) {
         ...
    }
}

Ответ 11

Контрактный ответ по вашему запросу также будет моим решением:

if (myClass.SessionExists)
{
   // Do something with myClass.Session
}

Ответ 12

Мы всегда возвращаем пустые списки/коллекции и не возвращаем NULL-списки/коллекции, потому что обработка пустых коллекций/списков снижает нагрузку на вызывающие функции.

Nullable - nullables особенно полезны, когда вы хотите избежать обработки "нулевых" значений из баз данных. Вы можете просто использовать GetDefaultOrValue для любого типа Nullable, не беспокоясь о том, что значение базы данных равно null в ваших бизнес-объектах. Мы определяем Nullables обычно ТОЛЬКО в наших бизнес-объектах, и это тоже, где мы действительно хотим избежать проверки нулевых значений db и т.д.

Ответ 15

NULL означает неизвестный/неопределенный.

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

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