Fórum raise: quando usar e quando não usar #330609
03/10/2006
0
eu mostro uma mensagem customizada por mim e talvez ainda concatene com a mensagem do exception. Tipo assim:
try .. .. except on e: exception do begin //trata //trata messagebox(0, ´bla´, pchar(´blablabla´+e.message), 0); end; end;
só que hoje eu tive que ´encapsular´ alguns desses try.. except dentro de métodos de outras classes.
A minha pergunta é: devo usar raise exception.create(mensagem) ao inves de messagebox(mensagem) nas minhas classes? ou Os metodos devem retornar true ou false caso houve sucesso ou não? Como eu pegaria a mensagem de erro nese caso: ´um metodo XX da classe AA instancia um objeto da classe BB e executa um método qualquer, mas na execução do método da classe BB ocorre uma excessão. ´
Se ocorre uma exception a execução do porgrama para? como eu posso fazer pra configurar se vai mostrar mensagem ou gerar exception?
se eu fizer algo do tipo:
procedure RaiseOrShow(msg: string; Reraise: Boolean = True); begin if Reraise then raise Exception.Create(msg) else MessageBox(0, ´Erro!´, PChar(msg), ADV_ALERTA); end;
dá certo?
Grato!
Vitor Rubio
Curtir tópico
+ 0Posts
03/10/2006
Tnaires
Tudo isso depende do comportamento do seu método. Acredito que a maneira mais elegante seja colocar um raise Exception.Create(´Msg´) dentro dos métodos, e ´protegê-los´ com try / except no ambiente de execução. Exemplo:
procedure MeuMetodo; begin if CoisaRuim then raise Exception.Create(´Coisa ruim.´); end; procedure AmbienteExecucaoMeuMetodo; begin try MeuMetodo; except Application.MessageBox(PChar(E.Message), ´Erro´, MB_OK + MB_ICONERROR); end; end;
Inclusive, um tratamento genérico de exceções pode ser escrito para o evento OnException do Application, ou utilizando um AppEvents.
Mas e se você tiver alguma função que precise retornar algo, independendo das condições de erro? Nesse caso, o try / except vai pra dentro da função. O bloco except atribui ao Result um valor válido, mas que simbolize erro dentro do contexto do programa ( -1, por exemplo ).
Abraços
Gostei + 0
03/10/2006
Michael
TConection = class public function Connect: Boolean; end; ... begin Connection.Connect; Connection.ExecQuery(...); ... end;
Se a conexão falhar, vai ocorrer outro erro na linha abaixo pq eu não tratei o retorno do método. Se uma exceção fosse levantada de dentro de [b:c1efa33f78]Connect[/b:c1efa33f78], nada após seria executado.
Outro ponto: se vc utilizar valores de retorno em cada método, vai precisar usar um tipo mais flexivel do que [b:c1efa33f78]Boolean[/b:c1efa33f78], pq dificilmente a quantidade de erros passíveis de ocorrem será binária. E não é recomendável ´agrupar´ erros em um único significado, pois isso dificulta a localização do ponto exato do problema. Usando ainda o método [b:c1efa33f78]Connect [/b:c1efa33f78]da classe mostrada acima como exemplo, se ele retornar [b:c1efa33f78]False[/b:c1efa33f78], como será possível saber se o problema é pq a senha do usuário está incorreta, pq o banco informado não existe, ou pq simplesmente a rede está offline?
Nessas situações, costuma-se usar [b:c1efa33f78]Integer [/b:c1efa33f78]como tipos de retorno. Porém, em paralelo, vc vai ter que montar tabelas de códigos de erro, para poder saber o que um 1, 2 ou -1 significam. Isso não é bom, e tende a tornar a manutenção do código mais trabalhosa, pois o significado de cada código não será o mesmo em todos os métodos: 1 é uma coisa para o método Foo1, e outra para o método Foo2, etc.
Por estas e outras razões que eu recomendo utilizar exceções para notificar erros na aplicação.
[]´s
Gostei + 0
05/10/2006
Vitor Rubio
O meu caso é o seguinte: antes eu tratava a excessão dentro do método
e retornava, para quem o chamou, true ou false, para saber se houve erro ou não. Mas a exception era gravada num log e, as vezes, tambem era mostrada para o usuario num messagebox. Só que agora é diferente....
agora a minha classe não vai mais ser usada diretamente pela interface, mas vai ser ´encapsulada´ por um método de uma outra classe. Não sei se eu trato a exception da mesma maneira e se retornar false eu ´reraiso´ essa exception, ou se eu simplesmente mostro messagebox ou se eu deixo todo o tratamento na interface. Desse jeito eu nunca vou saber que erro que ocoreu, é verdade. Mas se eu deixar pra tratar tudo na interface, vou ter muitos códigos parcialmente repetidos para tratamento dessas excessões. Não sei uma outra forma de saber, mostrar e logar, na parte mais externa, o que aconteceu de errado na parte mais interna.
Gostei + 0
05/10/2006
Tnaires
Dessa forma, você trata as exceções em um canto só, sem repetição de código, e sem usar Application.MessageBox em classes que não deveriam tratar de janelas e interfaces com o usuário.
Gostei + 0
05/10/2006
Vitor Rubio
minhas classes instanciam objetos de outras classes, em varios niveis.
se ocorrer uma excesão num método e eu tratar e mostrar um messagebox, beleza, depois disso o metodo continua.
Mas se eu propagar a mensagem de erro já tratada, com uma mensagem minha, criando oexception, tipo raise exception.create(´minha mensagem de erro´) a aplicação trava aí, e não prossegue.
eu preciso que a aplicação prossiga, para poder dar um free nos objetos instanciados.
veja o exemplo:
procedure TForm1.Button1Click(Sender: TObject); var objeto : TStringList; begin objeto := TStringList.Create; raise Exception.Create(´teste´); ShowMessage(´testou?´); objeto.Free; end;
o objeto não vai ser liberado nunca, e isso ocorre em varios lugares. Alem disso, eu tenho log de erro por e-mail, por arquivo texto e por banco de dados...
Gostei + 0
05/10/2006
Tnaires
Exemplo: suponha que você tem um método particular que gere uma exceção:
TClasse = class public procedure MeuMetodo; end; procedure TClasse.MeuMetodo; begin raise Exception.Create(´Exceção criada.´); end;
A rotina genérica de erro pode tratar essa exceção, e gravá-la no log sem problemas, pois ela recebe uma referência à própria exceção como parâmetro ( vide evento OnException do componente AppEvents ). Para resolver o problema de liberação de objetos, faça:
with TClasse.Create do try MeuMetodo; finally Free; end;
Nesse caso, o objeto sempre será liberado após a execução do método, independente de haver exceção ou não.
Gostei + 0
06/10/2006
Vitor Rubio
TClasse = class public procedure MeuMetodo; end; procedure TClasse.MeuMetodo; var AlgumaCoisa: ToutraClasse; begin AlgumaCoisa := ToutraClasse.create; AlgumaCoisa.FazOQueTemQueFazer; If CoisaRuimAconteceu then raise Exception.Create(´Exceção criada.´); AlgumaCoisa.Free; //nunca vai entrar nessa linha end;
with TClasse.Create do try MeuMetodo; finally Free; //não adianta dar free aqui, porque o objeto "AlgumaCoisa" não vai ser liberado end;
Eu uso exceptions para, alem de mostrar as mensagens de algo ruim para o usuario, criar um log, mas eu não posso criar exceptions para coisas boas, esse é um problema. Outro problema é o seguinte: se eu criar uma função assim:
procedure RaiseOrShow(msg: string; Reraise: Boolean = True); begin if Reraise then raise Exception.Create(msg) else MessageBox(0, PChar(msg), ´Erro!´ , ADV_ALERTA); end;
eu queria saber se é correto, quando for mensagem boa fazer:
raisorshow(´mesnagem de sucesso´, false);
e quando for ruim fazer:
RaiseOrShow(´iih, Ferrô!´, true);
dá certo? o raise para no lugar certo? onde ele deverá ser tratado?
Gostei + 0
06/10/2006
Tnaires
No contra-exemplo que você citou, um finally viria a calhar:
TClasse = class public procedure MeuMetodo; end; procedure TClasse.MeuMetodo; var AlgumaCoisa: ToutraClasse; begin AlgumaCoisa := ToutraClasse.create; try AlgumaCoisa.FazOQueTemQueFazer; If CoisaRuimAconteceu then raise Exception.Create(´Exceção criada.´); finally AlgumaCoisa.Free; //Essa linha sempre será executada end; end;
A regra é: try/finally sempre deve ser usado quando um objeto que executa um método passível de exceção precisar ser liberado imediatamente após sua execução.
Sobre o RaiseOrShow, eu afirmo o seguinte: exceptions só devem ser utilizadas quando houver algum erro crítico no sistema, que possa comprometer sua execução. Para avisos, informações gerais, ´mensagens boas´ e etc, não use exceções. Seguindo essa afirmação, o RaiseOnShow perde todo o sentido.
Gostei + 0
06/10/2006
Vitor Rubio
try.. finally numa exception que você mesmo ´raisou´
quanto ao RaiseOrShow, é que eu queria usar a mesma maneira de mostrar uma mensagem, idependente de acontecer coisa ruim ou boa, então o raiseorshow mostraria mensagem caso acontecesse coisa boa ou geraria exception no caso de coisa ruim.
tipo assim:
RaiseorShow(mensagem, (a=b));
mas eh meio estranho, né?
Gostei + 0
06/10/2006
Vitor Rubio
procedure TForm1.Button1Click(Sender: TObject); var objeto : TStringList; begin try objeto := TStringList.Create; Exit; raise Exception.Create(´teste´); finally ShowMessage(´testou?´); ShowMessage(´testou mesmo´); objeto.Free; end; end;
O finally executa mesmo depois de um exit!!! :D:D:D:D
e eu não sabia disso! Era tudo o que eu queria. Muito obrigado, você me ajudou muito!!!
Gostei + 0
06/10/2006
Tnaires
Gostei + 0
06/10/2006
Vitor Rubio
eu estou usando o raise para propagar exceptions caousadas dentro de classes minhas para serem tratadas na interface com o usuario.
as vezes as exceptions não são geradas pelos meus objetos, mas sim por objetos usados por eles.
Então no exemplo:
try
MeuObjetoQueMandaEmail.Envia; //se der exception aqui, provavelmente é senha invalida ou coisa do tipo, e foi o idSmtp que gerou.
except
{a minha duvida á aqui: eu uso raise exception.create(´deu erro´) ou só raise?}
raise;
end;queria saber quando usar raise; e quando usar raise exception.create(´bla bla bla´), e tambem quando usar o:
on e: exception do begin raise ou raise exception; cuida da coisa ruim; end;
Gostei + 0
06/10/2006
Vitor Rubio
Gostei + 0
06/10/2006
Tnaires
try try raise Exception.Create(´Coisa ruim´); except on E: Exception do begin // Faz alguma coisa e repassa a exceção raise; end; end; except on E: Exception do begin // Trata a exceção repassada end; end;
O bloco try/except externo vai receber a exceção repassada.
Por falar em on E: Exception... Esse comando serve para tratar um tipo ( classe ) de exceção específico. Exemplo:
type ECoisaRuim = class(Exception); ECoisaPiorAinda = class(Exception); ... procedure MeuMetodo; begin try // Este método pode gerar ECoisaRuim ou ECoisaPiorAinda GerarException; except on E1: ECoisaRuim do begin // Tratamento para exceções do tipo ECoisaRuim end; on E1: ECoisaPiorAinda do begin // Tratamento para exceções do tipo ECoisaPiorAinda end; end; end;
[quote:6031bfc017=´vitor^_^´]Outra coisa: Se as exceptions são objetos da classe Exception, quem é que da free nelas?[/quote:6031bfc017]
Diretamente do help do delphi:
:wink:
Gostei + 0
07/10/2006
Vitor Rubio
e no caso do on e: exception do eu posso simplesmente usar para mudar a mensagem da exception antes de repassar ela pra frente, por exemplo:
try MetodoQuePodeGerarException; except on E: Exception do begin // Faz alguma coisa e repassa a exceção //Metodos que tratam o erro se necessário raise exception.create(´Minha mensagem personalisada com a original concatenada no final´ + #1310+ e.message); //o resto vai seer tratado depois, na classe que chamou esse metodo end; end;
Valew pela ajuda!
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)