Depois de ler meu "Como separar código de interface e código funcional (baseado em Delphi/VCL)", alguém mencionou uma pergunta, que é como lidar com erros em classes do lado do servidor.
Em estruturas baseadas em funções, geralmente usamos valores de retorno de função para indicar se a função foi executada com sucesso e para fornecer informações como tipos de erros. Portanto, haverá código no seguinte formato:
RetVal := SomeFunctionToOpenFile();
se RetVal = E_SUCCESSED então
...
senão se RetVal = E_FILENOTFOUND então
...
senão se RetVal = E_FILEFORMATERR então
...
mais então
...
É muito comum usar um método que retorne um código de erro, mas há dois problemas ao usar tal método:
1. Ele cria uma estrutura de ramificação longa e complicada (um grande número de instruções if ou case), tornando o processo de controle complicado.
2. Pode haver erros que não foram tratados (se o chamador da função não determinar o valor de retorno)
Exceções são uma solução orientada a objetos para tratamento de erros. Ele pode reportar erros, mas o que você precisa saber é que a exceção não é levantada por causa do erro, mas simplesmente porque raise é usado.
No Object Pascal, a palavra reservada elevada é usada para lançar exceções. A qualquer momento (mesmo que nenhum erro ocorra), raise causará a ocorrência de uma exceção.
As exceções podem fazer com que o código retorne imediatamente do ponto onde a exceção ocorre, protegendo assim a execução do código confidencial abaixo. Não há diferença entre retornar de uma função através de uma exceção e retornar de uma função normalmente (executando até o final da função ou executando Exit) para a própria função que lança a exceção. A diferença é que no final do chamador, após retornar por meio de uma exceção, os direitos de execução serão capturados pelos blocos try...except do chamador (se existirem). Se não houver nenhum bloco try...except no chamador, as instruções subsequentes não continuarão a ser executadas, mas retornarão ao chamador de nível superior até que um bloco try...except que possa tratar a exceção seja encontrado. Após o tratamento da exceção, as instruções após o bloco try...except continuarão a ser executadas e o controle será deixado na camada que trata a exceção. Quando o manipulador de exceção sente que o tratamento da exceção não está completo o suficiente, ele precisa que o chamador de nível superior continue o processamento. Ele pode lançar novamente a exceção (use um aumento simples;) e transferir o controle para o chamador de nível superior. .
Se não houver nenhuma predefinição de bloco try...except, a exceção final será capturada pelo bloco try...except mais externo da VCL que encapsula todo o programa.
Portanto, não haverá exceções não tratadas, ou seja, não haverá erros não tratados (embora erros e exceções não sejam equiparados). Essa também é a vantagem do mecanismo de exceção em relação ao uso de métodos que retornam códigos de erro. Além disso, após o lançamento da exceção, a direção do processo de controle fica muito clara e não fará com que o processo perca o controle.
Para dar um exemplo de como funcionam as exceções, suponha que queremos abrir um arquivo em um formato específico:
Primeiro defina duas classes de exceção (herdadas de Exception)
EFileNotFound = classe(Exceção);
EFileFormatErr = classe(Exceção);
Suponha que haja um botão no Form1 e pressionar o botão abre o arquivo:
Procedimento TForm1.Button1Click(Remetente: TObject);
começar
tentar
ToOpenFile();
exceto
em EFileNotFound faça
ShowMessage('Desculpe, não consigo encontrar o arquivo');
onEFileFormatErr fazer
ShowMessage('Desculpe, o arquivo não é o que eu quero');
em E:Exceção fazer
ShowMessage(E.Mensagem);
fim;
fim;
E a função para abrir o arquivo:
procedimento ToOpenFile;
varRetVal:Inteiro;
começar
//Algum código para abrir o arquivo
RetVal := -1; //falha ao abrir
se RetVal = 0 então //sucesso
Saída
senão se RetVal = -1 então
Levante EFileNotFound.Create('Arquivo não encontrado')
senão se RetVal = -2 então
Raise EFileFormatErr.Create('Erro de formato de arquivo')
else //outro erro
Raise Exception.Create('Erro desconhecido');
fim;
No programa, TForm1.Button1Click chama ToOpenFile e predefinições try...exceto para lidar com exceções que podem ser lançadas por ToOpenFile. Claro, o código de tratamento de exceções de TForm1.Button1Click também pode ser simplificado:
procedimento TForm1.Button1Click(Remetente: TObject);
começar
tentar
ToOpenFile();
exceto
ShowMessage('Falha ao abrir arquivo');
fim;
fim;
O uso de exceções resolve os problemas de uso de métodos que retornam códigos de erro. É claro que o uso de exceções não é isento de custos. As exceções aumentarão a carga do programa, portanto não é aconselhável abusar das exceções. Há uma grande diferença entre escrever algumas tentativas...exceto e escrever milhares de tentativas...exceto. Nas palavras de Charlie Calverts: "Você deve usar blocos try...except quando parecer útil. Mas tente não ficar muito entusiasmado com essa técnica."
Além disso, Object Pascal introduz uma estrutura try...finalmente exclusiva. Eu disse antes que não há diferença entre retornar de uma função através de uma exceção e retornar de uma função normalmente. Portanto, os objetos locais na pilha da função serão liberados automaticamente, mas os objetos na pilha não. No entanto, o modelo de objeto do Object Pascal é baseado em referências, que existem no heap, não na pilha. Portanto, às vezes precisamos limpar alguns recursos de objetos locais antes de retornar de uma função por meio de uma exceção. tente... finalmente resolve esse problema.
Reescrevi o código ToOpenFile acima, desta vez usando alguns recursos durante o processo ToOpenFile e liberando esses recursos após a exceção ocorrer (ou não ocorrer) antes de retornar da função:
procedimento ToOpenFile;
varRetVal: Inteiro;
Fluxo: TStream;
começar
//Algum código para abrir o arquivo
Fluxo := TStream.Create;
RetVal := -1; //falha ao abrir
tentar
se RetVal = 0 então //sucesso
Saída
senão se RetVal = -1 então
Levante EFileNotFound.Create('Arquivo não encontrado')
senão se RetVal = -2 então
Raise EFileFormatErr.Create('Erro de formato de arquivo')
else //outro erro
Raise Exception.Create('Erro desconhecido');
finalmente
Stream.Grátis;
fim;
fim;
Percorrendo o código acima, podemos ver que mesmo quando o valor de RetVal for 0, após a execução de Exit, o código em finalmente ainda será executado e retornará da função. Isso garante a liberação correta dos recursos locais.
Os propósitos e cenários de uso de try...except e try...finally são diferentes e muitos iniciantes os confundem. A seguir estão alguns conhecimentos pessoais do autor: try...except geralmente é usado pelo chamador para capturar exceções lançadas pelas funções chamadas e tratá-las. E try...finally geralmente é usado para a função que lança a exceção para realizar algum trabalho de limpeza de recursos.
A programação orientada a objetos fornece uma solução de tratamento de erros chamada "exceção". Usado com sabedoria, beneficiará nosso trabalho e poderá melhorar significativamente a qualidade do código que escrevemos.
Nicrosoft ([email protected]) 25/07/2001
Fonte original: Documento Sunistudio (http://www.sunistudio.com/asp/sunidoc.asp)