Sou um grande fã de escrever declarações, contratos ou qualquer outro tipo de cheque disponível no idioma que estou usando. Uma coisa que me incomoda um pouco é que não tenho certeza de qual é a prática comum para lidar com verificações duplicadas.
Exemplo de situação: primeiro escrevo a seguinte função
void DoSomething( object obj )
{
Contract.Requires<ArgumentNullException>( obj != null );
//code using obj
}
algumas horas depois, escrevo outra função que chama a primeira. Como tudo ainda está fresco na memória, decido não duplicar o contrato, pois sei que já DoSomething
verificaremos um objeto nulo:
void DoSomethingElse( object obj )
{
//no Requires here: DoSomething will do that already
DoSomething( obj );
//code using obj
}
O problema óbvio: DoSomethingElse
agora depende DoSomething
para verificar se obj não é nulo. Portanto, deve DoSomething
sempre decidir não verificar mais, ou se eu decidir usar outra função, o obj pode não ser mais verificado. O que me leva a escrever essa implementação, afinal:
void DoSomethingElse( object obj )
{
Contract.Requires<ArgumentNullException>( obj != null );
DoSomething( obj );
//code using obj
}
Sempre seguro, não se preocupe, exceto que, se a situação aumentar, o mesmo objeto poderá ser verificado várias vezes e é uma forma de duplicação e todos sabemos que isso não é tão bom.
Qual é a prática mais comum para situações como essas?
fonte
ArgumentBullException
? Esse é um novo :)Respostas:
Pessoalmente, eu verificaria nulo em qualquer função que falhará se receber um nulo, e não em qualquer função que não.
Portanto, no seu exemplo acima, se doSomethingElse () não precisar desreferenciar obj, então eu não verificarei obj para null aqui.
Se DoSomething () desreferenciar obj, deverá procurar nulo.
Se ambas as funções a desreferenciarem, elas deverão verificar. Portanto, se as desreferências DoSomethingElse forem objetivas, ele deve procurar nulo, mas o DoSomething também deve procurar nulo, pois pode ser chamado de outro caminho.
Dessa forma, você pode deixar o código razoavelmente limpo e ainda garantir que as verificações estejam no local correto.
fonte
DoSomething()
forma que a pré-condição não seja mais necessária (improvável nesse caso específico, mas possa ocorrer em uma situação diferente) e remova a verificação de pré-condição. Agora, algum método aparentemente totalmente não-relacionado está quebrado por causa da falta de pré-condição. Vou usar um pouco de duplicação de código para ter clareza sobre falhas estranhas como essa de um desejo de salvar algumas linhas de código, a qualquer dia.Ótimo! Vejo que você descobriu o Code Contracts for .NET. Os contratos de código vão muito além das afirmações médias, das quais o verificador estático é o melhor exemplo. Talvez isso não esteja disponível para você se você não tiver o Visual Studio Premium ou superior instalado, mas é importante entender a intenção por trás disso, se você usará os Contratos de Código.
Quando você aplica um contrato a uma função, literalmente é um contrato . Essa função garante um comportamento de acordo com o contrato e é garantida para ser usada apenas conforme definido pelo contrato.
No seu exemplo, a
DoSomethingElse()
função não cumpre o contrato especificado porDoSomething()
, pois nulo pode ser passado e o verificador estático indicará esse problema. A maneira de resolver isso é adicionando o mesmo contrato aDoSomethingElse()
.Agora, isso significa que haverá duplicação, mas essa duplicação é necessária quando você optar por expor a funcionalidade em duas funções. Essas funções, embora privadas, também podem ser chamadas de lugares diferentes da sua classe; portanto, a única maneira de garantir que, a partir de qualquer chamada, o argumento nunca seja nulo, é duplicar os contratos.
Isso deve fazer você reconsiderar por que você dividiu o comportamento em duas funções em primeiro lugar. Sempre foi minha opinião ( contrária à crença popular ) que você não deve dividir funções que são chamadas apenas de um lugar . Ao expor o encapsulamento aplicando os contratos, isso se torna ainda mais evidente. Parece que encontrei uma argumentação extra para minha causa! Obrigado! :)
fonte