Penso que existem muitas armadilhas no Exemplo 2, que no futuro poderiam levar a códigos não intencionais. O primeiro do foco aqui é baseado na lógica em torno da variável 'myString'. Portanto, para ser explícito, todos os testes de condições devem ocorrer em um bloco de código que contabilize lógica conhecida e padrão / desconhecida .
E se, mais tarde, o código for introduzido acidentalmente no exemplo 2 que alterou significativamente a saída:
if (myString == null)
{
return false;
}
//add some v1 update code here...
myString = "And the winner is: ";
//add some v2 update code here...
//buried in v2 updates the following line was added
myString = null;
//add some v3 update code here...
//Well technically this should not be hit because myString = null
//but we already passed that logic
myString = "Name " + myString;
// Do something more here...
return true;
Eu acho que com o else
bloco imediatamente após a verificação de um nulo, os programadores que adicionaram os aprimoramentos às versões futuras juntam toda a lógica, porque agora temos uma sequência de lógica não intencional para a regra original (retornando se o valor for nulo).
Eu acredito muito nisso em algumas das diretrizes C # no Codeplex (link para isso aqui: http://csharpguidelines.codeplex.com/ ) que afirmam o seguinte:
"Adicione um comentário descritivo se o bloco padrão (else) estiver vazio. Além disso, se esse bloco não for atingido, lance uma InvalidOperationException para detectar alterações futuras que possam ocorrer nos casos existentes. Isso garante um código melhor, porque todos os caminhos que o código pode percorrer foram considerados ".
Eu acho que é uma boa prática de programação ao usar blocos lógicos como este, sempre adicionar um bloco padrão (caso contrário, case: default) para explicar explicitamente todos os caminhos de código e não deixar o código aberto para consequências lógicas não intencionais.