Что является лучшей практикой при возвращении данных из функции. Лучше возвратить null или пустой объект? И почему необходимо использовать один вариант по сравнению с другим.
Рассмотрим следующий вариант:
public UserEntity GetUserById(Guid userId)
{
//Здесь код доступа к базе данных...
//Проверяем вернувшиеся данные и возвращаем null если ничего не найдено
if (!DataExists)
return null;
//Или же я должен вернуть пустой объект?
//return new UserEntity();
else
return existingUserEntity;
}
Перевод
Ответ
Выбор между null и null-объектом зависит от того, как метод будет использоваться.
Примеры
Получение коллекции пользователей
ICollection
Как этот метод будет использоваться? Скорее всего, примерно так:
foreach (User user in userService.GetAllUsers()) {
// Обработка или отображение конкретного юзера
}
Возвращение пустой коллекции в этом случае нам позволит сэкономить на одном if (foreach не умеет игнорировать null). Нам неважно, были какие-то элементы в коллекции или нет, логика вызывающего метода от этого обычно не зависит. Если же зависит, то мы всегда можем воспользоваться свойством Count
Получение одного пользователя
User GetUser(int id);
Как этот метод будет использоваться? Скорее всего, примерно так:
User user = userService.GetUser(id);
if (user == null) {
// Всё плохо, обработать ошибку
}
else {
// Обработать или отобразить пользователя
}
В этом случае разумно вернуть null, потому что наличие и отсутствие результата предполагает различное поведение вызывающего кода.
Чего точно не следует делать — это возвращать new User(): это не позволит нормально проверить, существует запрошенный пользователь или нет. Если уж делать null-объекты, то они по возможности должны быть в единственном экземпляре и неизменяемы.
Получение текущего пользователя
User GetCurrentUser();
Как этот метод будет использоваться? Скорее всего, примерно так:
User currentUser = userService.GetCurrentUser();
Console.WriteLine("{0} ({1})", currentUser.Name, currentUser.Level);
В этом случае обработка пользователя обычно не зависит от наличия или отсутствия реального пользователя, поэтому можно вернуть объект "пользователь-гость". В случае, если проверка требуется, то можно реализовать свойство вроде User.IsRegistered или User.AccessLevel
Планы на будущее
В C# 7 планируется добавить разделение между nullable и non-nullable для reference-типов (в дополнение к value-типам). Тогда методы выше будут выглядеть так:
ICollection
Если вызвать метод GetUser и не проверить на значение null, то компилятор выдаст предупреждение.
ReSharper
Если у вас есть R#, то вы можете добавить аннотации уже сейчас:
[NotNull, ItemNotNull]
ICollection
Эти аннотации позволят анализатору R# явно разделять, что может быть null, а что не может, и за счёт этого предупреждать пользователя о потенциальных ошибках.
Комментариев нет:
Отправить комментарий