Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't System.Exception.ToString call virtual ToString for inner exceptions?

Tags:

c#

.net

mono

This is the actual source for .NET's System.Exception.ToString:

public override string ToString()
{
  return this.ToString(true, true);
}

private string ToString(bool needFileLineInfo, bool needMessage)
{
  string str1 = needMessage ? this.Message : (string) null;
  string str2 = str1 == null || str1.Length <= 0 ? this.GetClassName() : this.GetClassName() + ": " + str1;
  if (this._innerException != null)
    str2 = str2 + " ---> " + this._innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine + "   " + Environment.GetRuntimeResourceString("Exception_EndOfInnerExceptionStack");
  string stackTrace = this.GetStackTrace(needFileLineInfo);
  if (stackTrace != null)
    str2 = str2 + Environment.NewLine + stackTrace;
  return str2;
}

Apart from the sheer ugliness, one can notice that for all inner exceptions the private, non-virtual ToString will be called. In other words, if you overload ToString in your exception it won't get called if your exception happens to be nested. Oh, hold on, turns out built-in exceptions have same problems, e.g. System.IO.FileNotFoundException prints out path of the file - it is not a part of the Message:

public override string ToString()
{
  string str = this.GetType().FullName + ": " + this.Message;
  if (this._fileName != null && this._fileName.Length != 0)
    str = str + Environment.NewLine + Environment.GetResourceString("IO.FileName_Name", new object[1]
    {
      (object) this._fileName
    });
  ...
}

But if you wrap an instance... this information will be lost, unless you traverse the exceptions tree yourself and detect exceptions' type or call ToString yourself and do some mundane parsing.

That's an annoying inconvenience, making logging/writing error dialogs either lose information or being bug-prone. Interestingly, Mono gets it right.

Is there any hidden wisdom in .NET's version?

EDIT: this is not opinion based question. While I find this design choice annoying, I would like to know the benefits of this approach. Knowing them may be beneficial when desiging new solutions.

like image 902
gwiazdorrr Avatar asked Dec 16 '13 00:12

gwiazdorrr


People also ask

Does exception ToString include inner exception?

The default implementation of ToString obtains the name of the class that threw the current exception, the message, the result of calling ToString on the inner exception, and the result of calling Environment.

Does exception ToString include Stacktrace?

ToString() contains a description of the exception along with a complete stack trace.

How can I see inner exceptions?

When you're debugging and you get an exception, always, always, always click on the View Details link to open the View Details dialog. If the message in the dialog isn't expanded, expand it, then scan down to the Inner Exception entry.

Does Stacktrace include message?

The stack trace contains the Exception's type and a message, and a list of all the method calls which were in progress when it was thrown.


2 Answers

Exception.ToString() is not something that should be presented to users. It is something that should be presented to developers, perhaps in a log file.

The default implementation of ToString() normally does the "right thing". Notice how it does handle nested exceptions, and multiple exceptions (like AggregateException or SqlException), and even exceptions across a remoting boundary. Try getting an error during the deserialization of XML with the XML serializer, and you'll really appreciate how much information it gives you - usually enough to point directly to the cause of the exception.

If there is something specific that you would like to see displayed, then you should engage Microsoft on this issue. In particular, you're not likely to get them to simply call your overridden ToString. Clearly, the do not want to. However, if there is something your ToString wanted to display that theirs does not, then talk to them and see if there's another way to go about it, or if there's something they can do in a future release.

like image 66
John Saunders Avatar answered Oct 19 '22 07:10

John Saunders


In my experience, not including the inner exception details in the call to ToString is the correct decision by the framework designers.

Often, the result of ToString is presented to the end user in the event that the executing application cannot provide the user with more precise information on the nature of the problem and possible solutions.

In this case, nesting internal exception details can not only be confusing to the end user, it could also present a potential security risk. The example of the file name problem above is a good one: I would not want to expose the directory information of a file on my web server to an external user in the event the file could not be found (in theory, the exception would always be correctly handled to prevent this exposure, but no application is perfect).

Where the inner exception details become useful is in logging the application fault somewhere (event log, file, database, etc.). In this case, you will most likely want more than just the ToString details, so the implication is that since you have to have logging code for these situations anyway, this logging code is what is responsible for extracting the appropriate information.

I believe that Microsoft realized this early on since one of the first Application Blocks that they added to their Enterprise Library was the Exception Handling block, which provides an in-depth traversal and recording of all exception details, including public properties on the exceptions themselves.

like image 37
competent_tech Avatar answered Oct 19 '22 07:10

competent_tech