Devo fazer minhas próprias exceções ou cooptar exceções semelhantes para propósitos ligeiramente fora do padrão?

8

Essa é uma pergunta geral de design, mas estou focada em C # e .NET porque essas são as linguagens com as quais estou trabalhando agora.

Devo criar minhas próprias novas classes de exceção ou cooptar exceções de estrutura existentes para propósitos ligeiramente diferentes?

Por exemplo, estou precisando de uma exceção que indique que um membro (isto é, de um tipo por exemplo) era esperado, mas não foi encontrado durante a leitura de uma montagem usando Mono.Cecil. A biblioteca de classes base define a exceção MissingMemberException, que parece comunicar exatamente o que eu quero, mas a descrição diz:

A exceção é lançada quando há uma tentativa de acessar dinamicamente um membro da classe que não existe.

O que não se encaixa exatamente, porque não estou acessando dinamicamente o membro, mas trabalhando com a montagem passivamente.

GregRos
fonte
O que você deseja é reutilizar o nome, mas não o tipo. Há um significado específico associado a MissingMemberException. Basta definir um novo tipo que seja específico da sua estrutura e carregue exatamente o significado correto.
usr

Respostas:

7

Em geral

Subclassificar exceções é uma boa idéia para agrupar as exceções nas famílias ou agrupamentos aos quais eles pertencem. Também permite ao código do cliente a oportunidade de lidar com exceções com base em erros específicos ou de maneira mais geral. Normalmente, divido a árvore em algum lugar próximo à raiz entre os erros lógicos e de tempo de execução (por exemplo, em C ++ the std::runtime_errorvs. std::logic_error).

Ser capaz de diferenciar entre as exceções do sistema e as exceções do seu aplicativo também é uma boa idéia. Seria estranho se o código do cliente estivesse observando uma falha do sistema de algum tipo, mas capturasse o erro lógico do código (por meio de uma classe base).

Dado este caso e C #

O C # tem uma hierarquia rica e grande de exceções - eu não tentaria escolher uma classe base muito profunda nela. Seguindo o seu exemplo, parece que você está gerando um erro lógico (ou pelo menos um erro de aplicativo); portanto, a classe base ou mesmo essa exceção sugeriria um erro no sistema. A exceção exata pode ser debatida, mas acho que neste caso não é uma boa escolha.

Hierarquia

Eu criaria uma hierarquia que permita distinguir entre erros de sistema e de aplicativo e, posteriormente, entre erros de tempo de execução e erros lógicos. Não tenha medo de usar exceções internas - pegue o erro do sistema e envolva-o em algo mais significativo, considerando o contexto em que está sendo lançado. Não exagere, concentre-se no que seriam as principais exceções. As exceções podem ter descrições textuais exclusivas associadas a elas - use-as para fornecer ao usuário ainda mais detalhes ou dicas sobre o que fazer para corrigir o problema.

Niall
fonte
2
Essa é uma estratégia brilhante ao subclassificar exceções. Não tenho certeza se você está dizendo para subclassar exceções em todos os casos ou se você está simplesmente dizendo que quando você subclasse é assim que deve fazê-lo. Em relação à subclasse, concordo com a resposta postada por @DanielS.
Chuck Conway
3

A resposta é obviamente "depende", mas, considerando o seu caso de uso, eu diria que não. Aqui está o porquê:

O C # é uma linguagem orientada a objetos maravilhosa. É tão bom, de fato, que às vezes me pego tentando implementar uma visão fanaticamente purista do que começou como um projeto simples. Isso não me acontece muito quando se escreve JavaScript ou Objective-C ou PHP.

Quando entro nesse "modo", esse tipo de paralisia, um dos sintomas pode ser uma obsessão pelo tratamento de exceções, pelos genéricos e pela metaprogramação. Às vezes, os três juntos. É muito mais provável que seja um problema quando estou trabalhando em algo novo, relativamente desconhecido ou com especificações e objetivos de má qualidade. Em vez de me atrapalhar nos detalhes da implementação , acho, por que tentar criar algo que possa acomodar a maioria dos cenários que eu razoavelmente antecipo? Então, quando eu contornar os detalhes, os alicerces serão estabelecidos e eu escreverei vários métodos pequenos e atarracados, e assim por diante. Talvez alguém trabalhe no código da interface do usuário, eu apenas prestarei esses bons serviços e esses contratos ...

Infelizmente, isso ainda não aconteceu comigo. O que tende a acontecer é que eu começo por esse caminho trabalhando em "infraestrutura" - coisas como:

  • Escrevendo minhas próprias interfaces de contêiner IoC ou mexendo com Castle.Windsor
  • Determinando como lidarei com o mapeamento de tipos no aplicativo
  • Gravando a lógica do fluxo de controle para classes base abstratas que se assemelham Interceptors e agrupam chamadas para membros abstratos com manipulação de exceção
  • Criação de classes base abstratas para IRepository, IUnitOfWork, IDomainService, ICrossCuttingValidation, etc.
  • Tentando descrever um modelo de objeto hierárquico para algo cuja própria natureza nega tal meta-abordagem ( comoIFrameworkException )

Quando você se pergunta se a descrição de uma exceção é precisa o suficiente para o seu gosto, você está realmente negando que algum outro recurso crítico seja implementado. A natureza da exceção também é reveladora - não é uma exceção orientada a eventos , ocorre evidentemente longe de qualquer metodologia de entrada (como uma interface do usuário ou um pipe ou algo assim) e é provavelmente determinística por natureza - como em, você não pode prever o que um usuário digitará, mas você pode prever qual montagem você escolherá carregar ou outros enfeites.

A propósito, se a descrição o incomoda tanto, você não pode escrever um método de extensão para substituí-lo no escopo apropriado?

Então, isso é realmente apenas eu projetando minha própria paralisia de abstração e análise em você, mas acho que pode ser apropriado. Eu diria que, para permanecer no lado seguro, apenas subclasse an Exceptionquando:

  • Na verdade, você experimentou uma exceção de tempo de execução que deseja tratar em geral
  • A exceção de tempo de execução não é algo que você possa descartar razoavelmente em tempo de design
  • A exceção ainda não está bem coberta pelo grande número existente de Exceptionsubclasses
  • Você realmente tem uma ideia de como deseja lidar com a exceção OU, se não, apenas porque é tão complicado que você precisa pensar nela e voltar a ela.
  • Sua ideia vai além de alterar seus metadados, seu escopo, sua exceção interna etc., e lida mais com o objeto ou evento subjacente que produz a exceção e / ou os meios de realmente lidar com ele
  • Você já escreveu ou não é responsável pela maior parte do lado voltado para entrada de coisas como a interface do usuário
tacos_tacos_tacos
fonte
Agradeço sua abordagem pragmática. Como tudo depende.
Chuck Conway
1

Na minha opinião, as exceções personalizadas fazem sentido apenas em 2 casos:

1) você está desenvolvendo uma API

2) você o usa no seu código para se recuperar de uma falha.

Em qualquer outro cenário, as exceções integradas devem ser suficientes.

No seu caso, você pode usar InvalidArgumentException

DanielS
fonte
Você deve expandir um pouco sua resposta e fornecer um "Porquê" a cada marcador. Você está aqui. Criar exceções personalizadas é mais um sistema / hierarquia a ser mantido.
Chuck Conway