【问题标题】:Why doesn't System.Exception.ToString call virtual ToString for inner exceptions?为什么 System.Exception.ToString 不为内部异常调用虚拟 ToString?
【发布时间】:2013-12-16 00:40:40
【问题描述】:

这是 .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 的版本有什么隐藏的智慧吗?

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

【问题讨论】:

    标签: c# .net mono


    【解决方案1】:

    Exception.ToString() 不应该呈现给用户。它应该呈现给开发人员的东西,也许在一个日志文件中。

    ToString() 的默认实现通常会做“正确的事情”。注意它是如何处理嵌套异常和多个异常(如AggregateExceptionSqlException),甚至是跨远程边界的异常。尝试在使用 XML 序列化程序对 XML 进行反序列化期间遇到错误,您会非常感激它为您提供了多少信息 - 通常足以直接指出异常的原因。

    如果您希望看到显示的特定内容,那么您应该就这个问题与 Microsoft 联系。特别是,您不太可能让他们简单地调用您覆盖的 ToString。显然,不想。但是,如果您的 ToString 想要显示他们不希望显示的内容,请与他们交谈,看看是否有其他方法可以解决,或者他们是否可以在未来的版本中做些什么。

    【讨论】:

      【解决方案2】:

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

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

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

      内部异常细节变得有用的地方是在某处记录应用程序故障(事件日志、文件、数据库等)。在这种情况下,您很可能需要的不仅仅是 ToString 详细信息,因此这意味着由于无论如何您都必须拥有这些情况的日志记录代码,因此该日志记录代码负责提取适当的信息。

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

      【讨论】:

      • 我明白你的意思,但请注意,向用户显示异常堆栈和/或调用堆栈可能是一个安全漏洞。更不用说默认的ToString 也会打印Message 属性,它可能包含有意义的数据。因此,如果这是微软有意识的设计决定,它最终会成为一个既不提供安全性也不提供信息的中间地带。对于“零售”程序,您根本不应该显示ToString 的结果,对于内部技术,您需要更多信息(它就在那里!)。
      猜你喜欢
      • 2020-01-08
      • 2023-03-15
      • 2015-08-04
      • 2023-03-03
      • 1970-01-01
      • 2011-03-16
      • 2013-01-10
      • 2013-10-21
      • 2014-05-14
      相关资源
      最近更新 更多