Ultimamente tenho tido um pouco de debate com um colega de trabalho. Estamos usando especificamente o C #, mas isso pode se aplicar a qualquer idioma com tipos anuláveis. Digamos, por exemplo, que você tenha um valor que represente um máximo. No entanto, esse valor máximo é opcional. Argumento que um número anulável seria preferível. Meu colega de trabalho favorece o uso de zero, citando precedentes. É verdade que coisas como soquetes de rede costumam usar zero para representar um tempo limite ilimitado. Se eu escrevesse um código que lida com soquetes hoje, eu pessoalmente usaria um valor anulável, pois acho que isso representaria melhor o fato de que NÃO há tempo limite.
Qual representação é melhor? Ambos exigem uma verificação de condição para o valor que significa "nenhum", mas acredito que um tipo anulável transmite a intenção um pouco melhor.
fonte
Respostas:
Considerar:
Língua,
Estrutura,
Contexto.
1. Idioma
Usar ∞ pode ser uma solução para o máximo.
JavaScript, por exemplo, tem um infinito. C # não¹.
Ada, por exemplo, tem intervalos. C # não.
Em C #, existe
int.MaxValue
, mas você não pode usá-lo no seu caso.int.MaxValue
é o número inteiro máximo, 2.147.483.647. Se no seu código, você tem um valor máximo de algo, como uma pressão máxima aceita antes que algo exploda, usar 2.147.483.647 não faz sentido.2. Enquadramento
O .NET Framework é bastante inconsistente nesse ponto, e seu uso de valores mágicos pode ser criticado.
Por exemplo,
"Hello".IndexOf("Z")
retorna um valor mágico-1
. É talvez torna mais fácil (não é?) Para manipular o resultado:em vez de usar uma estrutura personalizada:
mas não é intuitivo. Por que
-1
e não-123
? Um iniciante também pode pensar erroneamente que0
significa "Não encontrado" também ou apenas digitar errado(position >= 0)
.3. Contexto
Se o seu código estiver relacionado a tempos limites nos soquetes de rede, usar algo que foi usado por todos por décadas para manter a consistência não é uma má idéia . Especialmente,
0
pois um tempo limite é muito claro: é um valor que não pode ser zero. Usar uma classe personalizada nesse caso pode tornar as coisas mais difíceis de entender:Duration
como 0 seIsTimeoutEnabled
for verdadeiro?IsTimeoutEnabled
for falso, o que acontece se eu definirDuration
como 100?Isso pode levar a vários erros. Imagine o seguinte pedaço de código:
A operação é executada por dez segundos. Você consegue ver o que há de errado com esse código, sem ler a documentação da
Timeout
classe?Conclusão
null
expressa bem a ideia de que o valor não está aqui. Não é fornecido. Não disponível. Não é um número, nem uma string zero / vazia ou qualquer outra coisa. Não o utilize para valores máximos ou mínimos.int.MaxValue
está fortemente relacionado à própria linguagem. Não useint.MaxValue
para um limite máximo de velocidade daVehicle
classe ou uma velocidade máxima aceitável para uma aeronave etc.Evite valores mágicos como
-1
no seu código. Eles são enganosos e levam a erros no código.Crie sua própria classe, que seria mais direta, com os valores mínimo / máximo especificados. Por exemplo,
VehicleSpeed
pode terVehicleSpeed.MaxValue
.Não siga nenhuma diretriz anterior e não use valores mágicos se for uma convenção geral por décadas em um campo muito específico, usado pela maioria das pessoas que escreve código nesse campo.
Não se esqueça de misturar abordagens. Por exemplo:
¹ Você pode criar seu próprio tipo, que inclui o infinito. Aqui, estou falando
int
apenas do tipo nativo .fonte
int
não estiver expressando o suficiente sobre o tipo para restringir o problema, considere uma nova estrutura com mais informações (instâncias constantes da estrutura que representam valores mágicos, por exemplo, ou uma enumeração para indicar). Ou considere a programação de contratos ou outras soluções, mas acho que uma estrutura personalizada é mais direta.Nulo não é melhor que um número mágico.
O importante é NOMEAR os valores que têm efeitos mágicos, se você precisar deles, e garantir que as definições desses nomes estejam em algum lugar que seja visto por qualquer pessoa que colidir com o valor mágico e o wtf.
fonte
MAGIC_NUMBER
absolutamente sempre deve ser evitado o código sempre que possível.null
é uma expressão de intenção muito mais clara.fonte
Em C #, muitas classes CLR têm um
Empty
membro estático :System.String.Empty
System.EventArgs.Empty
System.Guid.Empty
System.Drawing.Rectangle.Empty
System.Windows.Size.Empty
Isso evita que você precise se lembrar de usar um valor mágico ou nulo para construir um objeto vazio.
Mas e se você estiver lidando com um tipo de valor simples como um
int
? Nesse caso, considere se você está sendo vítima da Obsessão Primitiva . É bem possível que sua propriedade numérica aparentemente simples se beneficie de sua própria classe ou estrutura, o que permitiria especificar oEmpty
membro e também adicionar outro comportamento específico a esse tipo de valor.fonte
Nesse caso, o valor nulo é uma ótima maneira de indicar que não há um máximo. Geralmente, quando o caso especial significa que o valor em questão não se aplica, que você simplesmente não deseja o recurso que ele configura, null é uma boa indicação disso.
Um problema ao usar null para representar casos especiais é que existe apenas um valor nulo e pode haver vários casos especiais. Nesse caso, eu passaria uma enumeração como um parâmetro adicional, que pode indicar um caso especial, ou para usar o valor int normalmente. (Isso é essencialmente o que o Nullable <> faz por você, embora ele use um booleano em vez de uma enumeração e combine os parâmetros em uma única estrutura.)
fonte
Nesse caso, acho que um tipo anulável faz todo sentido.
Nulo significa ausência de valor. Esse é um conceito distintamente diferente de um número com valor 0.
Se você quiser dizer "Se eu não fornecer um valor, use o máximo", passar nulo é a maneira correta exata de expressar isso.
fonte
Nulo: valor de erro comum, não especificado, nulo ou ausência de valor.
Zero: um valor real, mas não necessariamente lógico ou intuitivo (neste contexto). Também é um valor comum na inicialização.
No contexto do seu problema, a
timeoutInMilliseconds
propriedade é opcional e não há menção de que a sobrecarga dessa abordagem a desqualificaria como uma opção.Conclusão: Existem exceções e as soluções variam de acordo com o idioma e o domínio; neste caso, eu escolheria nulo. Onde (acredito) algumas pessoas entendem isso errado é quando não separam bem os dados da interface. Eles esperam que qualquer cliente leia a documentação (ou implementação) para determinar como esses valores especiais devem ser usados / manipulados - os casos especiais vazam para o programa do cliente e isso pode não ser claro. Ao adicionar uma boa camada de abstração, o uso pode ser muito mais claro.
fonte
Nulo é pior do que usar
MagicNumber
. Nulo representa a idéia expressa melhor, mas não é consistente entre as plataformas na maneira como se comporta, usarMagicNumber
sempre funciona da mesma maneira, o que é benéfico.dependendo do ambiente / idioma usado null poderia
MagicNumber
sempre se comporta da mesma maneira.fonte
Se você esquecer de verificar o número mágico (acontecerá corretamente), um número mágico continuará por um tempo com dados sem sentido. Muito melhor ter um nulo que cause uma exceção o mais rápido possível.
fonte
Nulo não é a única alternativa a um número mágico.
Nulo é mau. No exemplo acima, você pode se safar disso, pois o código obviamente seria capaz de lidar com um nulo. Mas, em geral, o que acontece quando você começa a passar nulos é que mais cedo ou mais tarde você recebe uma exceção de ponteiro nulo. Pode não acontecer quando você escreve o código pela primeira vez, mas o código é mantido por muito mais tempo do que apenas a primeira versão. É frequentemente mantido por pessoas que não sabem tanto sobre o sistema quanto os desenvolvedores originais.
Scala (por exemplo) tem uma boa alternativa na classe Option. A classe Option possui um dos dois valores, alguns - que agrupam o valor que você realmente deseja e nenhum - que não têm valor.
Isso torna óbvio para qualquer desenvolvedor que pode não haver um valor e você tem um código melhor para isso. Bem, deve tornar óbvio de qualquer maneira.
E nem todos os números mágicos são um problema. Dependendo do contexto 0, 1, 1024, etc., tudo pode ser óbvio. 347? Sim, esse você deve evitar. :-)
fonte