Me deparei com esta página do MSDN que afirma:
Não lance Exception , SystemException , NullReferenceException ou IndexOutOfRangeException intencionalmente de seu próprio código-fonte.
Infelizmente, não se preocupa em explicar o porquê. Posso adivinhar as razões, mas espero que alguém com mais autoridade no assunto possa oferecer sua visão.
Os dois primeiros fazem algum sentido óbvio, mas os dois últimos parecem aqueles que você gostaria de empregar (e na verdade, eu usei).
Além disso, essas são as únicas exceções que devemos evitar? Se houver outros, quais são e por que também deveriam ser evitados?
c#
exception-handling
DonBoitnott
fonte
fonte
NullArgumentException
que algumas pessoas podem confundir os dois.ApplicationException
Respostas:
Exception
é o tipo base para todas as exceções e, como tal, terrivelmente inespecífico. Você nunca deve lançar essa exceção porque ela simplesmente não contém nenhuma informação útil. A captura do código de chamada para exceções não pode eliminar a ambigüidade da exceção lançada intencionalmente (de sua lógica) de outras exceções do sistema que são totalmente indesejadas e apontam falhas reais.O mesmo motivo também se aplica a
SystemException
. Se você olhar a lista de tipos derivados, poderá ver um grande número de outras exceções com semânticas muito diferentes.NullReferenceException
eIndexOutOfRangeException
são de um tipo diferente. Essas são exceções muito específicas, portanto, pode ser bom jogá-las . No entanto, você ainda não vai querer jogá-los, pois eles geralmente significam que existem alguns erros reais em sua lógica. Por exemplo, a exceção de referência nula significa que você está tentando acessar um membro de um objeto que énull
. Se isso for uma possibilidade em seu código, você deve sempre verificar explicitamentenull
e lançar uma exceção mais útil (por exemploArgumentNullException
). Da mesma forma,IndexOutOfRangeException
s ocorrem quando você acessa um índice inválido (em matrizes - não em listas). Você deve sempre certificar-se de não fazer isso em primeiro lugar e verificar os limites de, por exemplo, um array primeiro.Existem algumas outras exceções como essas duas, por exemplo
InvalidCastException
ouDivideByZeroException
, que são lançadas para falhas específicas em seu código e geralmente significam que você está fazendo algo errado ou não está verificando alguns valores inválidos primeiro. Ao descartá-los conscientemente de seu código, você está apenas tornando mais difícil para o código de chamada determinar se eles foram lançados devido a alguma falha no código ou apenas porque você decidiu reutilizá-los para algo em sua implementação.Claro, existem algumas exceções (hah) a essas regras. Se você estiver construindo algo que pode causar uma exceção que corresponda exatamente a uma existente, sinta-se à vontade para usar isso, especialmente se estiver tentando corresponder a algum comportamento integrado. Apenas certifique-se de escolher um tipo de exceção muito específico.
Em geral, porém, a menos que você encontre uma exceção (específica) que preencha sua necessidade, você deve sempre considerar a criação de seus próprios tipos de exceção para exceções esperadas específicas. Especialmente quando você está escrevendo código de biblioteca, isso pode ser muito útil para separar as fontes de exceção.
fonte
IList
implementação, não está em seu poder afetar os índices solicitados, é o erro lógico do chamador quando um índice é inválido, e você só pode informá-los desse erro lógico lançando uma exceção apropriada. Por queIndexOutOfRangeException
não é apropriado?IList
, irá lançar umArgumentOutOfRangeException
conforme sugere a documentação da interface .IndexOutOfRangeException
é para matrizes e, até onde eu sei, você não pode reimplementar matrizes.NullReferenceException
geralmente é lançado internamente como um caso especial de umAccessViolationException
(IIRC, o teste é algo comocmp [addr], addr
, isto é, ele tenta desreferenciar o ponteiro e se falhar com uma violação de acesso, ele trata a diferença entre NRE e AVE no manipulador de interrupção resultante). Portanto, além das razões semânticas, também há algum engano envolvido. Também pode ajudar a desencorajá-lo de verificarnull
manualmente quando não é útil - se você vai lançar um NRE de qualquer maneira, por que não deixar o .NET fazer isso?Suspeito que a intenção com os 2 últimos é evitar confusão com exceções embutidas que têm um significado esperado. No entanto, sou da opinião que, se você está preservando a intenção exata da exceção : é a correta para
throw
. Por exemplo, se você estiver escrevendo uma coleção personalizada, parece totalmente razoável usarIndexOutOfRangeException
- mais claro e mais específico, IMO, do queArgumentOutOfRangeException
. E embora vocêList<T>
possa escolher o último, há pelo menos 41 lugares (cortesia do refletor) no BCL (sem incluir matrizes) que são projetadas sob medidaIndexOutOfRangeException
- nenhum dos quais é de "nível baixo" o suficiente para merecer isenção especial. Então, sim, acho que você pode argumentar com justiça que essa diretriz é boba. Da mesma forma,NullReferenceException
é bastante útil em métodos de extensão - se você deseja preservar a semântica que:joga um
NullReferenceException
quandoobj
énull
.fonte
SomeMethod()
não for necessário realizar o acesso de membro, é incorreto forçá-lo. Da mesma forma: considere esse ponto com os 41 locais no BCL que criam personalizadosIndexOutOfRangeException
e os 16 locais que criam personalizadosNullReferenceException
ArgumentNullException
vez de umNullReferenceException
. Mesmo se o açúcar sintático dos métodos de extensão permitir a mesma sintaxe do acesso de membro normal, ele ainda funciona de maneira muito diferente. E obter um NRE deMyStaticHelpers.SomeMethod(obj)
seria simplesmente errado.Como você assinalou, no artigo Criando e lançando exceções (Guia de programação C #) sob o tópico Coisas a serem evitadas ao lançar exceções , a Microsoft realmente lista
System.IndexOutOfRangeException
como um tipo de exceção que não deve ser lançado intencionalmente de seu próprio código-fonte.Em contraste, no entanto, no lançamento do artigo (Referência C #) , a Microsoft parece violar suas próprias diretrizes. Aqui está um método que a Microsoft incluiu em seu exemplo:
Portanto, a própria Microsoft não está sendo consistente ao demonstrar o lançamento de
IndexOutOfRangeException
em sua documentação parathrow
!Isso me leva a acreditar que, pelo menos para o caso de
IndexOutOfRangeException
, pode haver ocasiões em que esse tipo de exceção pode ser lançado pelo programador e considerado uma prática aceitável.fonte
Quando li sua pergunta, me perguntei em que condições alguém gostaria de lançar os tipos de exceção
NullReferenceException
,InvalidCastException
ouArgumentOutOfRangeException
.Na minha opinião, ao encontrar um desses tipos de exceção, eu (o desenvolvedor) fico preocupado com o aviso no sentido de que o compilador está falando comigo. Portanto, permitir que você (o desenvolvedor) lance tais tipos de exceção é equivalente a (o compilador) vender a responsabilidade. Por exemplo, isso sugere que o compilador deve agora permitir que o desenvolvedor decida se um objeto é
null
. Mas fazer essa determinação deve ser realmente trabalho do compilador.PS: Desde 2003, venho desenvolvendo minhas próprias exceções para poder lançá-las como quiser. Eu acho que é considerada uma prática recomendada fazer isso.
fonte
Colocando a discussão sobre
NullReferenceException
e deIndexOutOfBoundsException
lado:Que tal pegar e jogar
System.Exception
. Eu lancei muito esse tipo de exceção no meu código e nunca me incomodei com isso. Da mesma forma, muitas vezes eu pego o não específicoException
tipo , e também funcionou muito bem para mim. Então, por que isso?Normalmente, os usuários argumentam que devem ser capazes de distinguir as causas dos erros. Pela minha experiência, existem apenas algumas situações em que você deseja lidar com diferentes tipos de exceção de maneira diferente. Para aqueles casos, onde você espera que os usuários tratem os erros programaticamente, você deve lançar um tipo de exceção mais específico. Para outros casos, não estou convencido pela diretriz geral de melhores práticas.
Portanto, em relação ao lançamento
Exception
, não vejo razão para proibir em todos os casos.EDITAR: também na página MSDN:
Exagerar cláusulas catch com lógica individual para diferentes tipos de exceção também não é uma prática recomendada.
fonte