Eu tenho um pedaço de código que pode ser representado como:
public class ItemService {
public void DeleteItems(IEnumerable<Item> items)
{
// Save us from possible NullReferenceException below.
if(items == null)
return;
foreach(var item in items)
{
// For the purpose of this example, lets say I have to iterate over them.
// Go to database and delete them.
}
}
}
Agora, estou me perguntando se essa é a abordagem correta ou devo lançar uma exceção. Posso evitar a exceção, porque retornar seria o mesmo que iterar sobre uma coleção vazia, o que significa que nenhum código importante é executado de qualquer maneira, mas, por outro lado, possivelmente estou ocultando problemas em algum lugar do código, porque por que alguém iria querer chamar DeleteItems
com null
parâmetro? Isso pode indicar que há um problema em outro lugar no código.
Esse é um problema que geralmente tenho com métodos em serviços, porque a maioria deles faz alguma coisa e não retorna um resultado; portanto, se alguém passa informações inválidas, não há nada para o serviço fazer, então ele retorna.
fonte
Respostas:
Essas são duas perguntas diferentes.
Você deveria aceitar
null
? Isso depende da sua política geral sobrenull
a base de código. Na minha opinião, banirnull
todos os lugares, exceto onde explicitamente documentado, é uma prática muito boa, mas é uma prática ainda melhor seguir a convenção que sua base de código já possui.Você deve aceitar a coleção vazia? Na minha opinião: SIM, absolutamente. É muito mais esforço restringir todos os chamadores a coleções não vazias do que fazer a coisa matematicamente correta - mesmo que surpreenda alguns desenvolvedores que são duvidosos com o conceito de zero.
fonte
AhaINoticedYouPassingInNullException
quando o tempo de execução já oferece a facilidade de jogarNullReferenceException
para você, sem a necessidade de escrever nenhum código. Existe algum utilitário (por exemplo, sua ferramenta de cobertura de código informa se você tem ou não um teste de unidade para passar nulo no primeiro caso, mas não no último), mas nenhuma exceção deve ser tentada / capturada em todas as chamadas para o serviço, porque geralmente é um erro do programador.NullReferenceException
ou emAhaINoticedYouPassingInNullException
qualquer outro lugar, exceto no código de recuperação de desastres de alto nível. E que manipulador de exceção provavelmente deve criar um relatório de bug :-)null
- os controladores contêm clichê para capturar e continuar nesse caso também?ArgumentNullException
é superior a permitir que o código interno gere umaNullReferenceException
- puramente olhando para a mensagem de exceção, é óbvio que se trata de um erro de entrada e não de um erro lógico no corpo do método no local do lance, e garantir a saída antecipada significa que é mais provável que você tenha deixado outros dados em um estado válido, em vez de ter sofrido uma mutação parcial de um nulo inesperado posteriormente.Valor nulo
Como o @KilianFoth já disse, atenha-se à sua política geral. Se isso for tratado
null
como um "atalho" para uma lista vazia, faça-o dessa maneira.Se você não tem uma política consistente de
null
valores, recomendo a seguinte:null
deve ser reservado para representar situações que não podem ser expressas pelo tipo "normal", por exemplo, usarnull
para representar "não sei". E essa é uma boa escolha, pois todos que tentarem usar esse valor descuidadamente receberão uma exceção, que é a coisa certa.Usar
null
como atalho para uma lista vazia não se qualifica dessa maneira, pois já existe uma representação perfeita, sendo uma lista com zero elementos. E é uma escolha tecnicamente ruim, pois força todas as partes do seu código que lidam com listas a procurar a abreviação válidanull
.Lista vazia
Para um
DeleteItems()
método, passar uma lista vazia efetivamente significa não fazer nada. Eu permitiria isso como argumento, não lançando uma exceção, apenas retornando rapidamente.Obviamente, o chamador pode verificar se há zero elementos primeiro e pular a
DeleteItems()
chamada nesse caso. Se estamos falando de uma API da Web, por motivos de eficiência, o chamador deve realmente fazer isso para evitar tráfego desnecessário e latências de ida e volta. Mas não acho que sua API imponha isso.fonte
Lance uma exceção e lide com nulos no código de chamada.
Como regra de design, tente evitar nulo como valores de parâmetro. Isso reduzirá NullPointerExceptions em geral, pois os nulos serão realmente uma exceção.
Além disso, observe o restante do seu código. Se esse é um padrão comum em seu projeto, mantenha-se consistente.
fonte
De um modo geral, o lançamento de exceções deve ser reservado para situações excepcionais, ou seja, se o código não tiver um curso de ação razoável a ser adotado no contexto atual.
Você pode aplicar esse processo de pensamento a essa situação. Dado que esta é uma classe pública com um método público, você tem uma API pública e, em teoria, não tem controle sobre o que é passado para ela.
Seu código não tem contexto sobre o que está chamando (como não deveria) e não há nada que você possa razoavelmente fazer com um valor nulo. Isso certamente seria um candidato a um
ArgumentNullException
.fonte
null
?null
você não tem coleção. Se o código de chamada deve / deve fornecer uma coleção para o método, há algo errado, então você deve lançar. O único motivo para tratar um nulo da mesma forma que uma coleção vazia é se você razoavelmente esperar que o código de chamada produza coleções nulas. Como outras respostas observadas, na maioria das vezes, algonull
é uma anomalia. Se você as tratar da mesma forma que coleções vazias, você estará potencialmente ignorando um problema em outra parte do código.null
entender que está vazio, isso é específico do contexto para esse método. Em algum outro lugar na mesma base de código, você pode ter um parâmetroIEnumerable
ouIContainer
que faz algum tipo de filtragem,null
pode significar "sem filtro" (permitir tudo), enquanto um filtro vazio significa não permitir nada. E em outro lugar,null
pode significar explicitamente "eu não sei". Portanto, dado quenull
nem sempre significa a mesma coisa em todos os lugares, é uma boa idéia não inventar nenhum significado para isso, a menos que esse significado seja necessário ou pelo menos útil para alguém.Esta questão parece não ser sobre exceções, mas sobre
null
ser um argumento válido.Portanto, primeiro e acima de tudo, você deve decidir se
null
é um valor permitido para o argumento desse método. Se for, você não precisa de uma exceção. Caso contrário, você precisará de uma exceção.Se você deseja permitir
null
ou não, é discutível, como mostra muitos e muitos hits do Google sobre isso. Ou seja, você não receberá uma resposta clara, e isso depende de opinião e tradição no local em que você está trabalhando.Outra área de disputa é se uma função de biblioteca deve ser realmente rigorosa sobre tais coisas ou o mais branda possível, desde que não esteja tentando "corrigir" parâmetros errados. Compare isso com o mundo dos protocolos de rede, transferência de e-mail etc. (que são contratos de interface, assim como métodos de programação). Geralmente, a política é que o remetente esteja em conformidade o mais estritamente possível com o protocolo, enquanto o destinatário deve fazer o possível para poder trabalhar com o que estiver por vir.
Então você tem que decidir: é realmente o trabalho de um método de biblioteca impor políticas bastante grandes, como
null
manipulação? Especialmente se sua biblioteca também for usada por outras pessoas (que podem ter políticas diferentes).Eu provavelmente
null
erraria ao permitir valores, definindo e documentando suas semânticas (ou seja,null = empty array
neste caso), e não lançaria uma exceção, a menos que 99% de seu outro código semelhante (código de estilo "biblioteca") faça isso de outra maneira 'volta.fonte
null
aceitar o princípio de ser liberal no que aceita, fazer logon ou até jogar seria útil para pessoas cuja intenção é ser rigorosa no que elas passam, mas que confundiram tanto o código quanto seus testes de unidade na medida em que eles passam denull
qualquer maneira.null
, mas declarar abertamente no contrato do método que é aceitável (ou não, dependendo de qualquer solução que o OP surja) e, então, a questão de lançar uma exceção (ou não) se resolve.