invocando métodos dentro de uma expressão condicional

4

Em uma referência mais citada (se datada) para os padrões de codificação C # (pdf ; de Lance Hunt), a declaração é feita,

33. Avoid invoking methods within a conditional expression.

Eu não vi essa recomendação em nenhum outro lugar, inclusive nas diretrizes do .NET ( aqui ou aqui ). Ao contrário das outras diretrizes muito razoáveis no documento de Hunt, essa sugestão parece não intuitiva para mim. Alguém pode fornecer uma justificativa para isso?

    
por kmote 16.06.2014 / 18:08
fonte

4 respostas

9
Bem, eu não li o documento de Hunt na íntegra, mas parece que o conselho dele é principalmente sobre legibilidade. Uma declaração como ...

if(myObject1.functionA() && myObject1.functionB())
{
  // do something
}

... tem um certo risco de ser mal interpretado, por causa da avaliação de curto-circuito, e também por causa do comprimento da linha if. Em vez disso ...

bool resultOfA = myObject1.functionA();
bool resultOfB = myObject1.functionB();

if(resultOfA && resultOfB)
{
  // do something
}

... é mais fácil de ler e sempre chamará ambas as funções (). É claro que, se você quiser usar a avaliação de curto-circuito (talvez porque a função B não deva ser chamada quando a função A retornar falso), talvez seja melhor ignorar as regras do Hunt (nota: ele diz "evite", não "não faça isso em nenhuma circunstância").

    
por 16.06.2014 / 18:25
fonte
5

Você também deve considerar as chamadas de função que têm efeitos colaterais (por exemplo, alterar algumas variáveis globais). Essa pode ser uma questão mais importante do que apenas legibilidade.

if (funcA() && funcB()) ...

Pode ser intencional que o funcB só seja chamado quando o funcA for bem-sucedido, mas você também pode cometer um erro aqui. Se ambas as funções tiverem efeitos colaterais e ambos forem necessários para serem executados, então o código acima é logicamente defeituoso. Isso pode acontecer porque o programador era ambicioso demais para manter seu código firme, mas também pode ser que estivesse correto antes, mas devido a algumas mudanças em algum outro lugar, as suposições tomadas não são mais válidas.

Portanto, nunca é uma boa ideia chamar funções com efeitos colaterais dentro de uma expressão booleana.

    
por 16.06.2014 / 23:36
fonte
4

Primeiro, fica claro no contexto que conditional expression Hunt significa a expressão booleana em uma instrução condicional. Esta é uma seção sobre controle de fluxo, e não sobre o uso de expressões booleanas para outros propósitos, ou sobre (o que eu chamaria) expressões condicionais baseadas no operador ternário '?:'.

Acredito que a intenção subjacente aqui é que as partes de uma expressão condicional usada para controle de fluxo devem evitar mal-entendidos que possam surgir de uma avaliação de curto-circuito ou de efeitos colaterais. Não consigo ver nenhuma razão para evitar funções de método de chamada para obter valores usados em uma expressão condicional (desde que não haja efeitos colaterais) e não vejo nenhum problema dependendo da avaliação de curto-circuito desde que as relações entre as partes da expressão estejam claramente visível. É o risco de conexões ocultas e consequências ocultas que devem ser evitadas. Então:

if (x.Contains(a) && x.Median() > b) {} // ok
if (x.Insert(a) && x.Median() > b) {} // NOT ok

Existe uma consideração adicional. A chamada de um método pode envolver uma penalidade de desempenho, portanto, se Median () for lento para computar:

if (x.Median() >= a && x.Median() <= b) {} // slower
var median = x.Median();
if (median >= a && median <= b) {} // faster
Tendo dito tudo isso, acho que Hunt nos faz um desserviço ao não explicar o que ele quer dizer. Espero que uma versão futura resolva essa falha.

    
por 17.06.2014 / 05:41
fonte
3

Ele encoraja o carregamento de várias chamadas de função na condicional e, em seguida, depende da avaliação de curto-circuito para lidar com a ramificação.

Quando isso acontece, seu programa fica mais difícil de depurar. Se você tem 5 funções dentro de um único condicional e tudo que você sabe é que o condicional falhou ... Então você é forçado a depurar por degraus os pontos de parada condicionais ou de spam para ver o que realmente está sendo chamado. Na verdade, é provavelmente mais rápido refatorar nesse ponto e colocar cada chamada de função em sua própria linha.

Parece inofensivo a princípio, e sim você estará salvando linhas. Mas quando o seu trabalho em um grande projeto carregado com este estilo, ou o seu projeto crescer e você estiver usando esse estilo, isso adicionará tempo aos seus esforços de depuração. Você deveria programar como se fosse quebrar, porque vai quebrar.

    
por 29.03.2016 / 18:25
fonte