Перевірка, чи метод повертає значення false: призначити результат тимчасовій змінній, або поставити виклик методу безпосередньо в умовний?


9

Чи є гарною практикою викликати метод, який повертає істинні чи помилкові значення у операторі if?

Щось на зразок цього:

private void VerifyAccount()
{
    if (!ValidateCredentials(txtUser.Text, txtPassword.Text))
    {
        MessageBox.Show("Invalid user name or password");
    }
}

private bool ValidateCredentials(string userName, string password)
{
    string existingPassword = GetUserPassword(userName);
    if (existingPassword == null)
        return false;

    var hasher = new Hasher { SaltSize = 16 };
    bool passwordsMatch = hasher.CompareStringToHash(password, existingPassword);

    return passwordsMatch;
}

або краще зберігати їх у змінній, а потім порівнювати їх за допомогою інших значень, таких як ця

bool validate = ValidateCredentials(txtUser.Text, txtPassword.Text);
if(validate == false){
    //Do something
}

Я маю на увазі не тільки .NET, я посилаюся на питання на всіх мовах програмування. Так буває, що я використовував .NET як приклад


3
Якщо ви використовуєте тимчасову змінну, пишіть, if (!validate)а не if (validate == false).
Філіп

12
Я б назвав функцію чимось на кшталт "CredentialsAreValid ()", тож ви знаєте, що вона повинна повертати булінг, але в іншому випадку - так, її хороша практика
Zachary K

3
IsValidCredentials, хоча граматично незручно, є загальним форматом для вказівки булевого повернення значення.
zzzzBov

@Philip Яка різниця між if (! Validate) і цим if (валідатом) ??
KyelJmD

!є оператором "НЕ", він заперечує будь-яке булеве вираження. Так if (!validate)є навпаки if (validate). Заява if буде введено, якщо validateце неправда.
Філіп

Відповіді:


26

Як і у всіх цих речах, це залежить.

Якщо ви не збираєтеся використовувати результат свого дзвінка, ValidateCredentialsтоді немає необхідності (крім випадків налагодження) зберігати результат у локальній змінній. Однак, якщо він робить код читабельнішим (і, отже, більш доступним), матиме змінну.

Код не стане помірно менш ефективним.


1
це тип читабельного? як той, що я робив вище
KyelJmD

@KyelJmD: Це залежить від культури, яку ви програмуєте. У місцях, в яких я запрограмований, програма !ValidateCredentialsє більш читаною, оскільки вона чітко говорить про те, що вона робить у коді. Це дуже зрозуміло. Якщо функція, яку ви викликаєте, не має імені "самодокументування", тоді може бути краще перейти зі змінною. На даний момент я рекомендую опустити змінну і залишитися з кодом самодокументації, який у вас є.
Джоел Етертон

ValidateCredentials в першу чергу не читається - як назва говорить вам, що означає результат? Набагато краще або CredentialsAreValid або CredentialsAreInvalid.
gnasher729

9

Навіщо використовувати додаткову змінну? Я вважаю за краще використовувати перший підхід, він читабельніший і простіший.


4

Чи є гарною практикою викликати метод, який повертає істинні чи помилкові значення у операторі if?

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

або краще зберігати їх у змінній, а потім порівнювати їх за допомогою інших значень, таких як ця

Ви повинні зробити це лише в тому випадку, якщо ви використовуєте значення в декількох місцях або вам потрібно, щоб зробити код більш читабельним. Інакше присвоєння змінній непотрібне. Непотрібний код - у кращому випадку марнотратний, а в гіршому - джерело дефекту.


2

Подивимося...

Оскільки це все про KISS , не потрібно створювати додаткову змінну, коли можна обійтися без неї. Крім того, немає потреби вводити більше ... коли немає необхідності.

Але тому, що ви СУХА , якщо ви пізніше дзвонили ValidateCredentialsі знаходите себе, набираючи текст, ValidateCredentials(txtUser.Text, txtPassword.Text)ви знаєте, що вам слід створити додаткову змінну.


2

Так, зазвичай добре застосовувати такі методи, як якщо б умови. Це корисно, хоча якщо назва методу вказує, що метод повертає bool; наприклад, CanValidateCredentials. У мовах стилю С цей метод часто має форму префіксів Is and Can, а в Ruby - "?" суфікс.


1
Хороша думка про назви методів, але я ніколи не запускати ім'я методу з "якщо". Тоді код зазначає "якщо". "Можна" нормально : if (cat.canOpenCanOfCatFood()).
Кевін Клайн

Дякую, @Kevin. Я мав на увазі "Є" не "Якщо". Я відредагував відповідь
Крістіан Хорсдал

1

Є ще одна проблема, яка ще не була зазначена: оцінка короткого замикання . Яка різниця між цими двома фрагментами коду?

Приклад №1:

if(foo() && bar() && baz())
{
    quz();
}

Приклад №2:

bool isFoo = foo();
bool isBar = bar();
bool isBaz = baz();
if(isFoo && isBar && isBaz)
{
    quz();
}

Ці два фрагменти коду, схоже, роблять те саме, але якщо ваша мова підтримує оцінку короткого замикання, ці два фрагменти відрізняються. Оцінка короткого замикання означає, що код оцінить мінімум, необхідний для проходження або відмови умови. Якщо приклад №1, якщо foo () повертає значення false, bar () і baz () навіть не оцінюються. Це корисно, якщо baz () - тривалий виклик функції, оскільки ви можете пропустити його, якщо або foo () повертає false, або foo () повертає true, а bar () повертає false.

Це не так у прикладі №2. foo (), bar () і baz () завжди оцінюються. Якщо ви очікуєте, що бар () і baz () проявлять побічні ефекти, у вас виникнуть проблеми з прикладом №1. Приклад №1 вище фактично еквівалентний цьому:

Приклад №3:

if(foo())
{
    if(bar())
    {
        if(baz())
        {
            quz();
        }
    }
}

Будьте в курсі цих відмінностей у своєму коді, обираючи між прикладами №1 та №2.


1

Трохи розширюємо питання читабельності ...

Я можу придумати дві вагомі причини зберігати результат у змінній:

  1. Якщо ви будете використовувати умову не один раз, збереження її у змінній означає, що вам потрібно викликати функцію лише один раз. (Це передбачає, що збережене значення все ще є дійсним; якщо вам потрібно повторно протестувати його, звичайно, це не застосовується.)

  2. Якщо зберігання його у змінній покращує читабельність, надаючи умові ім'я, яке має більше значення, ніж те, що ви бачите у виклику функції.

Наприклад, це:

bool foo_is_ok = is_ok(foo);
if (foo_is_ok) ...

не допомагає читати, але це:

bool done_processing = feof(file1) && feof(file2);
if (done_processing) ...

ймовірно, так, оскільки це не відразу очевидно, що це feof(file1) && feof(file2)означає, що ми закінчили обробку.

passwordsMatchЗмінної в питанні, ймовірно, кращий приклад , ніж мій.

Змінні для одноразового використання корисні, якщо вони дають змістовну назву якомусь значенню. (Це, звичайно, на користь людському читачеві.)


Думаю, я краще відмовлюсь замість введення done_processingзмінної. Адже ім’я done_processingвиконує функцію коментаря. І справжній коментар дозволяє мені сказати одне-два слова про те, чому цей стан сигналізує, що ми робимо обробку. Не те, що я чудовий коментатор, хоча, мабуть, я б не зробив жодного в реальному коді ...
cmaster - відновити моніку

@cmaster: Одна з проблем з коментарями полягає в тому, що вони можуть дуже легко вийти з синхронізації з кодом. Названа змінна done_processing- більш довговічний спосіб вираження наміру.
Кіт Томпсон

+1 для точки №2 - іноді добре названий темп-вар дійсно прояснює речі.
user949300
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.