Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception.ToString broken in .NET 4.0?

Tags:

.net

exception

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?

like image 845
Kim Gräsman Avatar asked Nov 09 '12 08:11

Kim Gräsman


1 Answers

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

like image 183
Patko Avatar answered Nov 04 '22 14:11

Patko