Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Warum zeigt Application.ShowException(..) die INNERSTE? (https://www.delphipraxis.net/186318-warum-zeigt-application-showexception-die-innerste.html)

Der schöne Günther 24. Aug 2015 09:22

Delphi-Version: XE7

Warum zeigt Application.ShowException(..) die INNERSTE?
 
Das macht doch irgendwie keinen Sinn. Folgendes Beispiel:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
resourcestring
   errorMsg = 'The calculation failed';
var
   divisor: Single;
   result: Single;
begin
   divisor := 0.0;
   try
      result := System.Pi() / divisor;
   except
      Exception.RaiseOuterException(
         EProgrammerNotFound.Create(errorMsg)
      );
   end;
end;
TApplication.ShowException(..) ist folgendermaßen definiert:
Delphi-Quellcode:
procedure TApplication.ShowException(E: Exception);
var
  Msg: string;
  SubE: Exception;
begin
  Msg := E.Message;
  while True do
  begin
    SubE := E.GetBaseException;
    if SubE <> E then
    begin
      E := SubE;
      if E.Message <> '' then
        Msg := E.Message;
    end
    else
      Break;
  end;
[...]
Was macht das für einen Sinn dem Benutzer "Floating Point division by Zero" statt "The calculation failed" anzuzeigen? Das ist doch grade der Sinn von geschachtelten Exceptions, dass ich hier sagen kann, was allgemein falsch lief, und nicht welches spezielle Byte umgefallen ist.

Erleuchtet mich. :wiejetzt:

TiGü 24. Aug 2015 10:54

AW: Warum zeigt Application.ShowException(..) die INNERSTE?
 
Na, zumindest bist du nicht der erste, der sich wundert:

http://eurekalog.blogspot.de/2010/05...09-and_05.html
Zitat:

Anyway, in both examples we leak important information: an information about previous exception, which can give us hints to the problem. And it is when nested exceptions appears.

The new exception class (whoa, that sure took a lot of time, but I should introduce newbies to nested exceptions after all) have InnerException and BaseException properties. Both properties are set (managed) by SysUtils unit automatically, you don't need to fill them manually. So, you can read and use them. InnerException property stores the previous exception. BaseException stores exception with most nested level - i.e. the very first exception, which started this exception chain. If there are only two exceptions in the chain (old and new, as in examples above), then InnerException will be equal to BaseException. If there is only one exception (i.e. there is no nested exception at all) - then both properties will be equal to nil.

Nested exceptions, however, aren't saved by default. In order to save nested exception, you need to raise new exceptions via Exception.RaiseOuterException (Delphi's style) or Exception.ThrowOuterException (C++ Builder's style). For example:

Delphi-Quellcode:
procedure TSomeClass.SaveToStream(const AStream: Stream);
begin
  try
    // ... saving instance to stream here
  except
    Exception.RaiseOuterException(ESomeClassSaveError.Create('Error saving data to stream'));
  end;
end;
After executing this code, we will get exception of ESomeClassSaveError class, which will have non-nil InnerException property (and BaseException too), which, in turn, will contain original exception (EStreamError or whatever it was).

In the second example (the one with exception in destructor) we still get InnerException = nil, cause RaiseOuterException isn't used anywhere.

How this support of nested exceptions affects error messages? Well, Message property didn't changed - it's a message of current exception only. So, any code, which isn't awared about nested exceptions, will show only message of the last exception. You can use ToString method of Exception class to show all messages from all exceptions - each exception will be on new line (obviously, ToString will be equal to Message property in case of single exception in the chain).

On the other side, Application.ShowException method looks a bit strange: this method shows message from BaseException - I suppose that it's not what you want (see our first example). That's why I think that you may want to make your own Application.OnException event handler to change this behaviour. For example:

Delphi-Quellcode:
procedure TForm1.ApplicationEvents1Exception(Sender: TObject; E: Exception);
var
  Msg: String;
begin
  Msg := E.Message; // or E.ToString
  Application.MessageBox(PChar(Msg), PChar(Application.Title), MB_OK + MB_ICONSTOP);
end;


Der schöne Günther 24. Aug 2015 10:57

AW: Warum zeigt Application.ShowException(..) die INNERSTE?
 
Danke für die seelische Bestätigung. Wenn man sich nicht alleine wundert, wundert man sich gleich viel weniger.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:34 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz