为什么System.Exception.ToString不为内部异常调用虚拟ToString?

时间:2013-12-16 00:40:41

标签: c# .net mono

这是.NET的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;
}

除了纯粹的丑陋之外,人们可以注意到对于所有内部异常,私有的非虚拟ToString将被称为。换句话说,如果您在异常中重载ToString,如果您的异常恰好嵌套,则不会调用它。哦,坚持,结果是内置异常有同样的问题,例如System.IO.FileNotFoundException打印出文件的路径 - 它不是消息的一部分:

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
    });
  ...
}

但是如果你包装一个实例......这个信息将会丢失,除非你自己遍历异常树并检测异常的类型或自己调用ToString并进行一些普通的解析。

这是令人烦恼的不便,使得记录/写入错误对话框丢失信息或容易出错。有趣的是,Mono gets it right

.NET版本中是否有任何隐藏的智慧?

编辑:这不是基于意见的问题。虽然我觉得这个设计选择很烦人,但我想知道这种方法的好处。在设计新的解决方案时,了解它们可能是有益的。

2 个答案:

答案 0 :(得分:2)

Exception.ToString()不应该呈现给用户。 应该提供给开发人员的东西,可能是在日志文件中。

ToString()的默认实现通常会执行“正确的事情”。请注意它如何处理嵌套异常和多个异常(如AggregateExceptionSqlException),甚至跨越远程边界的异常。尝试在使用XML序列化程序对XML进行反序列化时出错,并且您真的很了解它为您提供了多少信息 - 通常足以直接指出异常的原因。

如果您希望显示某些特定内容,那么您应该就此问题与Microsoft联系。特别是,你不可能让他们简单地调用你被覆盖的ToString。显然,不想。但是,如果你的ToString想要显示他们没有的东西,那么请与他们交谈,看看是否还有另一种方法,或者他们在将来的版本中可以做些什么。

答案 1 :(得分:1)

根据我的经验,在ToString调用中不包括内部异常细节是框架设计者的正确决定。

通常,如果执行的应用程序无法向用户提供有关问题性质和可能解决方案的更准确信息,则会向最终用户呈现ToString的结果。

在这种情况下,嵌套内部异常详细信息不仅会使最终用户感到困惑,还可能带来潜在的安全风险。上面的文件名问题的例子很好:我不希望在无法找到文件的情况下将我的Web服务器上的文件的目录信息暴露给外部用户(理论上,异常总是如此)正确处理以防止这种暴露,但没有应用是完美的。)

内部异常细节变得有用的地方是在某处记录应用程序故障(事件日志,文件,数据库等)。在这种情况下,您很可能不仅仅需要ToString详细信息,因此暗示因为您必须拥有针对这些情况的日志记录代码,所以此日志记录代码负责提取适当的信息。

我相信微软很早就意识到这一点,因为他们添加到企业库中的第一个应用程序块之一是Exception Handling block,它提供了对所有异常细节的深入遍历和记录,包括公共属性关于例外本身。