Eu li muitos artigos (e algumas outras perguntas semelhantes que foram postadas no StackOverflow) sobre como e quando usar asserções e as entendi bem. Mesmo assim, não entendo que tipo de motivação deveria me levar a usar em Debug.Assert
vez de lançar uma exceção simples. O que quero dizer é que, no .NET, a resposta padrão a uma declaração com falha é "parar o mundo" e exibir uma caixa de mensagem para o usuário. Embora esse tipo de comportamento possa ser modificado, acho altamente irritante e redundante fazer isso, enquanto eu poderia, em vez disso, apenas lançar uma exceção adequada. Dessa forma, eu poderia facilmente gravar o erro no log do aplicativo antes de lançar a exceção e, além disso, meu aplicativo não necessariamente congela.
Então, por que eu deveria, se fosse, usar em Debug.Assert
vez de uma exceção simples? Colocar uma asserção onde não deveria estar poderia causar todos os tipos de "comportamento indesejado", então, no meu ponto de vista, eu realmente não ganho nada usando uma asserção em vez de lançar uma exceção. Você concorda comigo ou estou faltando alguma coisa aqui?
Nota: Eu entendo perfeitamente qual é a diferença "em teoria" (Depurar versus Liberar, padrões de uso etc.), mas a meu ver, seria melhor lançar uma exceção em vez de executar uma declaração. Visto que se um bug for descoberto em uma versão de produção, eu ainda quero que a "asserção" falhe (afinal, a "sobrecarga" é ridiculamente pequena), então seria melhor lançar uma exceção.
Edit: A meu ver, se uma declaração falhou, isso significa que o aplicativo entrou em algum tipo de estado corrompido e inesperado. Então, por que eu iria querer continuar a execução? Não importa se o aplicativo é executado em uma versão de depuração ou lançamento. O mesmo vale para ambos
fonte
Respostas:
Embora eu concorde que seu raciocínio seja plausível - isto é, se uma afirmação é violada inesperadamente, faz sentido interromper a execução lançando - eu pessoalmente não usaria exceções no lugar de afirmações. Aqui está o porquê:
Como já foi dito, as assertivas devem documentar as situações impossíveis , de forma que caso a suposta situação impossível se concretize, o desenvolvedor seja informado. As exceções, por outro lado, fornecem um mecanismo de fluxo de controle para situações excepcionais, improváveis ou errôneas, mas não para situações impossíveis. Para mim, a principal diferença é esta:
Deve ser SEMPRE possível produzir um caso de teste que exerça uma determinada instrução de lance. Se não for possível produzir tal caso de teste, então você tem um caminho de código em seu programa que nunca é executado e deve ser removido como código morto.
NUNCA deve ser possível produzir um caso de teste que provoque o disparo de uma asserção. Se uma asserção for disparada, o código está errado ou a asserção está errada; de qualquer forma, algo precisa mudar no código.
É por isso que eu não substituiria uma afirmação por uma exceção. Se a asserção não puder realmente disparar, substituí-la por uma exceção significa que você tem um caminho de código não testável em seu programa . Não gosto de caminhos de código não testáveis.
fonte
As asserções são usadas para verificar a compreensão do programador sobre o mundo. Uma asserção deve falhar apenas se o programador tiver feito algo errado. Por exemplo, nunca use uma asserção para verificar a entrada do usuário.
Realiza teste para condições que "não podem acontecer". As exceções são para condições que "não deveriam acontecer, mas acontecem".
Assertions são úteis porque em tempo de construção (ou até mesmo tempo de execução) você pode mudar seu comportamento. Por exemplo, frequentemente em compilações de lançamento, as declarações nem são verificadas, porque introduzem sobrecarga desnecessária. Isso também é algo para se ter cuidado: seus testes podem nem mesmo ser executados.
Se você usar exceções em vez de declarações, perderá algum valor:
O código é mais detalhado, já que testar e lançar uma exceção tem pelo menos duas linhas, enquanto uma declaração é apenas uma.
Seu código de teste e lançamento sempre será executado, enquanto afirmações podem ser compiladas.
Você perde alguma comunicação com outros desenvolvedores, porque afirmações têm um significado diferente do código do produto que verifica e lança. Se você estiver realmente testando uma asserção de programação, use uma assert.
Mais aqui: http://nedbatchelder.com/text/assert.html
fonte
EDIT: Em resposta à edição / nota que você fez em sua postagem: Parece que usar exceções é a coisa certa a usar em vez de asserções para o tipo de coisas que você está tentando realizar. Acho que o obstáculo mental que você está atingindo é que está considerando exceções e afirmações para cumprir o mesmo propósito e, portanto, está tentando descobrir qual seria "certo" usar. Embora possa haver alguma sobreposição em como as asserções e exceções podem ser usadas, não confunda isso, por serem soluções diferentes para o mesmo problema - não são. Cada uma das afirmações e exceções tem seu próprio propósito, pontos fortes e fracos.
Eu ia digitar uma resposta com minhas próprias palavras, mas isso faz justiça ao conceito melhor do que eu faria:
Estação C #: Asserções
Basicamente, use exceções para coisas que precisam ser capturadas / tratadas em um aplicativo de produção, use asserções para realizar verificações lógicas que serão úteis para o desenvolvimento, mas desligadas na produção.
fonte
Acho que um exemplo prático (inventado) pode ajudar a iluminar a diferença:
(adaptado da extensão Batch MoreLinq )
Então, como Eric Lippert et al disseram, você apenas afirma coisas que espera que estejam corretas, apenas no caso de você (o desenvolvedor) acidentalmente ter usado errado em outro lugar, para que possa corrigir seu código. Basicamente, você lança exceções quando não tem controle sobre ou não pode antecipar o que chega, por exemplo , para a entrada do usuário , de modo que o que quer que tenha fornecido dados incorretos possa responder adequadamente (por exemplo, o usuário).
fonte
Outra pepita do Code Complete :
Ele acrescenta algumas diretrizes sobre o que deve e o que não deve ser afirmado.
Por outro lado, exceções:
Se você não tem este livro, deve comprá-lo.
fonte
Debug.Assert por padrão só funcionará em compilações de depuração, então se você quiser detectar qualquer tipo de comportamento inesperado em suas compilações de lançamento, você precisará usar exceções ou ativar a constante de depuração nas propriedades do projeto (que é considerado em geral não é uma boa ideia).
fonte
Use asserções para coisas que SÃO possíveis, mas não deveriam acontecer (se fosse impossível, por que você colocaria uma asserção?).
Não parece um caso para usar um
Exception
? Por que você usaria uma afirmação em vez de umException
?Porque deve haver um código que é chamado antes de sua declaração para impedir que o parâmetro da declaração seja falso.
Normalmente não há nenhum código antes de você
Exception
que garanta que ele não será lançado.Por que é bom que
Debug.Assert()
seja compilado no prod? Se você quiser saber sobre isso no debug, não gostaria de saber sobre isso no prod?Você quer isso apenas durante o desenvolvimento, porque, depois de encontrar as
Debug.Assert(false)
situações, você escreve o código para garantir queDebug.Assert(false)
isso não aconteça novamente. Assim que o desenvolvimento estiver concluído, supondo que você encontrou asDebug.Assert(false)
situações e as corrigiu, elesDebug.Assert()
podem ser compilados com segurança, pois agora são redundantes.fonte
Suponha que você seja membro de uma equipe bastante grande e que haja várias pessoas trabalhando na mesma base de código geral, incluindo a sobreposição de classes. Você pode criar um método que é chamado por vários outros métodos e, para evitar contenção de bloqueio, não adiciona um bloqueio separado a ele, mas "assume" que foi bloqueado anteriormente pelo método de chamada com um bloqueio específico. Como Debug.Assert (RepositoryLock.IsReadLockHeld || RepositoryLock.IsWriteLockHeld); Os outros desenvolvedores podem ignorar um comentário que diz que o método de chamada deve usar o bloqueio, mas eles não podem ignorar isso.
fonte