Verificando se um método retorna false: atribua resultado à variável temporária ou coloque a invocação do método diretamente em condicional?

9

É uma boa prática chamar um método que retorne valores verdadeiros ou falsos em uma instrução if?

Algo assim:

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;
}

ou é melhor armazená-los em uma variável e compará-los usando se mais valores como este

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

Não estou me referindo apenas ao .NET, estou me referindo à pergunta em todas as linguagens de programação. Acontece que usei o .NET como exemplo

KyelJmD
fonte
3
Se você usar uma variável temporária, escreva em if (!validate)vez de if (validate == false).
Philip
12
Eu chamaria a função de algo como "CredentialsAreValid ()" então você sabe que deve estar retornando um bool mas caso contrário sim a sua boa prática
Zachary K
3
IsValidCredentials, embora gramaticalmente estranho, é um formato comum para indicar um valor de retorno booleano.
zzzzBov
@ Philips Qual é a diferença entre if (! Validate) e this if (validate) ??
KyelJmD
!é o operador "NOT", ele nega qualquer expressão booleana. Então if (!validate)é o oposto de if (validate). A instrução if será inserida se validatenão for verdadeira.
26412 Philip Philip

Respostas:

26

Como com todas essas coisas, depende.

Se você não usar o resultado da sua chamada para ValidateCredentials, não será necessário (exceto para fins de depuração) armazenar o resultado em uma variável local. No entanto, se tornar o código mais legível (e, portanto, mais sustentável), uma variável será aceita.

O código não será mensurável menos eficiente.

ChrisF
fonte
11
esse tipo de legível? como o que fiz acima
KyelJmD 26/02/12
@KyelJmD: Isso depende da cultura em que você está programando. Nos lugares em que programei, !ValidateCredentialsé mais legível porque diz explicitamente o que está fazendo no código. Está muito claro. Se a função que você está chamando não tiver um nome de "auto-documentação", talvez seja melhor usar a variável Tal como está, eu recomendo omitir a variável e ficar com o código de auto-documentação que você possui.
Joel Etherton
O ValidateCredentials não é legível em primeiro lugar - como o nome diz o que o resultado significa? Muito melhor CredentialsAreValid ou CredentialsAreInvalid.
precisa saber é o seguinte
9

Por que usar uma variável adicional? Prefiro usar a primeira abordagem, é mais legível e simples.

Diego Pacheco
fonte
4

É uma boa prática chamar um método que retorne valores verdadeiros ou falsos em uma instrução if?

Sim, se o condicional não for simples o suficiente para incorporar e permitir que seja legível.

ou é melhor armazená-los em uma variável e compará-los usando se mais valores como este

Você só deve fazer isso se estiver usando o valor em vários locais ou precisar dele para tornar o código mais legível. Caso contrário, a atribuição a uma variável é desnecessária. Código desnecessário é, na melhor das hipóteses, um desperdício e, na pior das hipóteses, uma fonte de um defeito.

dietbuddha
fonte
2

Vamos ver...

Por se tratar de KISS , não há necessidade de criar uma variável adicional quando você pode ficar sem ela. Além disso, não há necessidade de digitar mais ... quando não há necessidade.

Mas, como você SECA , se você estava ligando mais tarde ValidateCredentialse se viu digitando, ValidateCredentials(txtUser.Text, txtPassword.Text)sabe que deveria ter criado uma variável adicional.

aredkid
fonte
2

Sim, geralmente é bom usar métodos como se fossem condições. É útil, porém, se o nome do método indicar que o método retorna um bool; por exemplo, CanValidateCredentials. Nas linguagens de estilo C, esse método geralmente assume a forma de prefixos Is e Can e, em Ruby, com o '?' sufixo.

Christian Horsdal
fonte
11
Bom argumento sobre nomes de métodos, mas eu nunca começaria um nome de método com "se". Em seguida, o código diz "se se". "Can" é ok: if (cat.canOpenCanOfCatFood()).
Kevin cline
Obrigado, @ Kevin. Eu quis dizer 'Não' não 'Se'. Eu editei a resposta
Christian Horsdal
1

Há outra preocupação que ainda não foi apontada: avaliação de curto-circuito . Qual é a diferença entre esses dois fragmentos de código?

Ex # 1:

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

Ex # 2:

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

Esses dois fragmentos de código parecem fazer a mesma coisa, mas se seu idioma suportar a avaliação de curto-circuito, esses dois fragmentos serão diferentes. A avaliação de curto-circuito significa que o código avaliará o mínimo necessário para passar ou falhar em uma condição. Se o exemplo 1, se foo () retornar false, bar () e baz () nem serão avaliados. Isso é útil se baz () for uma chamada de função de longa duração, porque você poderá ignorá-la se foo () retornar false ou foo () retornar true e bar () retornar false.

Este não é o caso no exemplo # 2. foo (), bar () e baz () são sempre avaliados. Se você espera que bar () e baz () exibam efeitos colaterais, você terá problemas com o Exemplo 1. O exemplo 1 acima é realmente equivalente a isso:

Ex # 3:

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

Esteja ciente dessas diferenças no seu código ao escolher entre os exemplos 1 e 2.

user2023861
fonte
1

Expandindo um pouco a questão da legibilidade ...

Posso pensar em duas boas razões para armazenar o resultado em uma variável:

  1. Se você estiver usando a condição mais de uma vez, salvá-la em uma variável significa que você só precisa chamar a função uma vez. (Isso pressupõe que o valor armazenado ainda é válido; se você precisar testá-lo novamente, é claro que isso não se aplica.)

  2. Se o armazenamento em uma variável melhorar a legibilidade, forneça à condição um nome mais significativo do que o que você vê na chamada de função.

Por exemplo, isto:

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

não ajuda a legibilidade, mas isso:

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

provavelmente sim, já que não é imediatamente óbvio que feof(file1) && feof(file2)significa que terminamos o processamento.

A passwordsMatchvariável na pergunta é provavelmente um exemplo melhor que o meu.

As variáveis ​​de uso único são úteis se atribuírem um nome significativo a algum valor. (Isso é claro para o benefício do leitor humano.)

Keith Thompson
fonte
Acho que prefiro deixar um comentário em vez de introduzir a done_processingvariável. Afinal, o nome done_processingtem a função de um comentário. E um comentário real me permite dizer uma ou duas palavras sobre por que essa condição sinaliza que terminamos o processamento. Não é que eu sou um grande comentarista, porém, eu provavelmente faria nem em código real ...
cmaster - Reintegrar monica
@ master: Um problema com os comentários é que eles podem facilmente ficar fora de sincronia com o código. Uma variável denominada done_processingé uma maneira mais durável de expressar a intenção.
Keith Thompson
+1 para o ponto número 2 - às vezes um temp var bem nomeado realmente esclarece as coisas.
user949300