5

I'm using a test framework that reports exceptions using Exception.ToString().

I ran into incomplete reporting of nested exceptions yesterday, and after some work with Reflector came to the conclusion that .NET 4.0 has broken how inner exception string representations are composed.

Here's an example;

public class MyException : Exception
{
  DateTime when;

  public MyException(DateTime when)
  {
    this.when = when;
  }

  public override string ToString()
  {
    var builder = new StringBuilder();
    builder.AppendFormat("Happened at: {0}\r\n", this.when);
    builder.Append(base.ToString());
    return builder.ToString();
  }
}

class Program
{
  private static void throws()
  {
    throw new Exception("bobby!", new MyException(DateTime.Now));
  }

  private static void catches()
  {
    try
    {
      throws();
    }
    catch (Exception e)
    {
      Console.WriteLine(e);
    }
  }

  static void Main(string[] args)
  {
    catches();
  }
}

The console output here will not contain my custom "Happened at" prefix.

Note that if we throw MyException directly, not nested in another exception, the custom string rep will be used.

It turns out the reason is that Exception.ToString() no longer calls the inner exception's ToString(), but rather a private method, ToString(bool), i.e.

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

private string ToString(bool needFileLineInfo)
{
  // yada yada

  if (this._innerException != null)
  {
    result += "some stuff " + this._innerException.ToString(needFileLineInfo) + " some more stuff";
                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
  }

  // yada yada

  return result;
}

So, since Exception.ToString() no longer calls the inner exception's ToString(), the implementation has short-circuited any opportunity of customized string representations for inner exceptions.

In .NET 2.0, the overridable ToString() was called as expected, so this was a breaking change somewhere along the way.

The docs haven't changed, and still claim that;

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 [...]

http://msdn.microsoft.com/en-us/library/system.exception.tostring.aspx

Does this sound like a bug to anyone but me?

svick
  • 236,525
  • 50
  • 385
  • 514
Kim Gräsman
  • 7,438
  • 1
  • 28
  • 41
  • 1
    Does not solve your issue bus little note, you should not derive your class from Exception, derive from: ApplicationException. - http://blog.gurock.com/articles/creating-custom-exceptions-in-dotnet – Davide Piras Nov 09 '12 at 08:29
  • 1
    Thanks! Changed example so as not to distract others :-) – Kim Gräsman Nov 09 '12 at 08:34
  • 6
    Regarding `ApplicationException` vs `Exception`, the guideline is to **not** use `ApplicationException`. Reference: http://stackoverflow.com/a/52770/66849 – PHeiberg Nov 09 '12 at 08:44
  • 3
    @DavidePiras that post doesn't appear to be timestamped, but as PHeiberg points out, it is giving **very out of date** advice. Note that [this](http://blogs.msdn.com/b/codeanalysis/archive/2006/04/05/faq-why-do-some-sources-recommend-extending-applicationexception-while-fxcop-does-not-michael-fanning-david-kean.aspx) blogs.msdn post *from 2006* says "this guidance was revised several years ago"... – AakashM Nov 09 '12 at 08:50
  • Oh, OK. Rolled back. Thanks, guys. – Kim Gräsman Nov 09 '12 at 08:53

1 Answers1

7

Yes, it appears to be a bug. Have a look at MS Connect issue.

Patko
  • 4,365
  • 1
  • 32
  • 27
  • Thank you! I spent a good while searching Connect yesterday, and couldn't find anything related. Now I'll just hold my breath until the next major release comes out :-) – Kim Gräsman Nov 09 '12 at 09:15
  • By the way, does anybody have a .NET 4.5 environment they could check this on? The issue was closed September 2010, so it feels like this should have made it into 4.5... Thanks! – Kim Gräsman Nov 09 '12 at 09:17
  • 1
    Unfortunately this is not fixed in .NET 4.5. You can also download source code from http://referencesource.microsoft.com/netframework.aspx and check for yourself. So if you really intend to hold your breath..nice knowing you :) – Patko Nov 09 '12 at 09:34