【问题标题】:C#: Overriding ToString() method for custom exceptionsC#:为自定义异常重写 ToString() 方法
【发布时间】:2010-12-25 14:08:44
【问题描述】:

我有一个自定义异常类,其中包含一些附加字段。我希望将这些写在ToString() 方法中,但是如果我实现自己的ToString(),我会丢失一些其他有用的东西(比如编写异常类型名称、内部异常数据和堆栈跟踪)。

针对此类异常实现您自己的ToString() 方法的最佳方式/模式是什么?理想情况下,它应该重用现有机制,但格式类似于默认的ToString() 实现。

更新:例如,将我的自定义字段添加或附加到 base.ToString() 文本并不理想,恕我直言

PimTool.Utilities.OERestServiceUnavailableException: test ---> System.InvalidOperationException: inner message
   --- End of inner exception stack trace ---
   at PimTool.Tests.Services.OE.OERestClientTests.ExceptionsLogging() in D:\svn\NewPimTool\PimTool.Tests\Services\OE\OERestClientTests.cs:line 178, 
   StatusCode=0, message='test', requestId='535345'

表示自定义字段写在(可能很长)异常描述的末尾。 另一方面,我希望异常类型是描述中写入的第一个信息。

更新 2:我已经为此实施了一个解决方案,请在下面寻找我自己的答案。

【问题讨论】:

  • 我正在寻找同样的东西,我想在 Message 字段之外添加一些额外的信息,但我希望保留 ToString 格式,所有堆栈跟踪和内部异常都在它。查看 Exception.ToString() 的代码并将其复制添加更多信息会很有趣。
  • 那么代码涵盖了您提到的大部分内容。虽然后来我记得我可以使用 Exception.Data 字典来存储我的自定义内容。我猜在那种情况下,这将使用 ToString() 的默认实现来呈现,但我还没有尝试过。

标签: c# .net exception tostring


【解决方案1】:

您可以通过查看异常属性手动将默认数据添加到ToString 返回的字符串中。比如下面会模拟异常的ToString方法默认返回的数据(假设没有内部异常):

string.Format("{0}: {1}\r\n{2}", this.GetType().Name, this.Message, this.StackTrace);

或者,您可以简单地将base.ToString 返回的数据附加(或前置)到您要添加的信息中。

【讨论】:

  • 这似乎是最接近我的想法的解决方案。虽然你忘了写出 InnerException ;)
【解决方案2】:

在覆盖调用 base.ToString() 中并根据您的需要修改生成的字符串...

【讨论】:

    【解决方案3】:

    您可以重写 ToString() 方法以包含您自己的自定义信息,并且仍然像这样调用默认的基本异常 ToString():

    public class MyException : Exception
    {
        public string CustomField { get; set; }
        public override string ToString()
        {
            return CustomField + Environment.NewLine + base.ToString();
        }
    }
    

    【讨论】:

      【解决方案4】:

      如果您主要在调试器中查看它们,那么您可以使用[DebuggerDisplay] 属性来指定它们的格式,而无需触及现有的ToString 方法。

      否则,只需重载ToString,并确保调用基类版本base.ToString()

      【讨论】:

      • 虽然不是我要找的,但提到它+1。
      【解决方案5】:

      好的,这就是我想出的。我已经实现了一个扩展类,它复制了格式化异常的原始机制,但有一个转折:一个自定义 Action 委托,它提供了一个用于格式化自定义字段的插件:

      public static class ExceptionFormatterExtensions
      {
          public static string ExceptionToString (
              this Exception ex, 
              Action<StringBuilder> customFieldsFormatterAction)
          {
              StringBuilder description = new StringBuilder();
              description.AppendFormat("{0}: {1}", ex.GetType().Name, ex.Message);
      
              if (customFieldsFormatterAction != null)
                  customFieldsFormatterAction(description);
      
              if (ex.InnerException != null)
              {
                  description.AppendFormat(" ---> {0}", ex.InnerException);
                  description.AppendFormat(
                      "{0}   --- End of inner exception stack trace ---{0}",
                      Environment.NewLine);
              }
      
              description.Append(ex.StackTrace);
      
              return description.ToString();
          }
      }
      

      现在您可以在自己的 ToString() 实现中使用此方法,而无需复制格式化代码:

          public override string ToString()
          {
              return this.ExceptionToString(
                  description =>
                  {
                      description.AppendFormat(
                          ", HttpStatusCode={0}, RequestId='{1}'", 
                          httpStatusCode, 
                          RequestId);
                  });
          }
      

      【讨论】:

        【解决方案6】:

        这一切都太过分了。您的异常应该只覆盖 Message 属性。

        public override String Message {
            get {  
                return base.Message + String.Format(", HttpStatusCode={0}, RequestId='{1}'", 
                            httpStatusCode, 
                            RequestId);
            }
        }
        

        Exception 类的默认 ToString 方法基本上是“ClassName: Message --&gt; InnerException.ToString() StackTrace”。因此,覆盖 Message 会将您的消息文本准确地放在应有的位置。

        【讨论】:

        • 除非你为了注入自定义堆栈跟踪而走这条路。
        • @yoyo,是的,但这不是 OP 的要求
        • 完全正确,您的回答很好。 (我来这里是为了寻找一些不同的东西。)
        • 这很好用,但我不确定它的风格是否很棒,至少可能并非总是如此,因为Message 属性不限于ToString 的使用。 new CustomException("My message").Message 返回字符串 != "My message" 可能是出乎意料的。如果他们想在某处显示/记录他们的消息而不是附加信息并假设Message 等于他们设置的消息,那可能会咬人。不是说这是错误的,而是要根据具体情况考虑。
        【解决方案7】:

        最简单的方法

        public override string ToString()
        {
            StringBuilder sb = new();
            var separator = new string[] { Environment.NewLine };
            var str = base.ToString().Split(separator, 2, StringSplitOptions.None);
            sb.AppendLine(str[0]);
        
            // Your properties
        
            sb.Append(str[1]);
            return sb.ToString();
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-11-09
          • 2021-08-24
          • 1970-01-01
          • 2022-06-23
          • 2012-07-02
          相关资源
          最近更新 更多