C#:重写自定义异常的 ToString() 方法

发布于 2024-08-14 03:55:58 字数 803 浏览 5 评论 0原文

我有一个自定义异常类,其中包含一些附加字段。我希望将它们写在 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:我已经为此实现了一个解决方案,请在下面查找我自己的答案。

I have a custom exception class which contains some additional fields. I want these to be written out in the ToString() method, but if I implement my own ToString(), I loose some other useful stuff (like writing the exception type name, the inner exception data and the stack trace).

What is the best way/pattern to implement your own ToString() method for such exceptions? Ideally it should reuse the existing mechanism, but be formatted in way similar to the default ToString() implementation.

UPDATE: prepending or appending my custom fields to the base.ToString() text isn't ideal IMHO, for example

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'

means the custom fields are written at the end of the (potentially long) exception description.
On the other hand, I want the exception type to be the first information written in the description.

UPDATE 2: I've implemented a solution for this, look for my own answer below.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

远山浅 2024-08-21 03:55:59

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

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

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

This is all overkill. Your exception should just override the Message Property.

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

The default ToString method for the Exception class is basically "ClassName: Message --> InnerException.ToString() StackTrace". So overriding the Message puts your message text exactly where it should be.

清秋悲枫 2024-08-21 03:55:59

好的,这就是我想出的。我已经实现了一个扩展类,它复制了格式化异常的原始机制,但有一个变化:一个自定义 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);
            });
    }

OK, this is what I came up with. I've implemented an extension class which replicates the original mechanism for formatting exceptions, but with a twist: a custom Action delegate which provides a plug-in for formatting custom fields:

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

Now you can use this method in your own ToString() implementations without duplicating the formatting code:

    public override string ToString()
    {
        return this.ExceptionToString(
            description =>
            {
                description.AppendFormat(
                    ", HttpStatusCode={0}, RequestId='{1}'", 
                    httpStatusCode, 
                    RequestId);
            });
    }
夜吻♂芭芘 2024-08-21 03:55:59

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

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

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

You could manually add the default data to the string returned by ToString, by looking at the exception properties. For example, the following will simulate the data returned by default by a exception's ToString method (assuming there are no inner exceptions):

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

Or, you could simply append (or prepend) the data returned by base.ToString to the information you want to add.

靑春怀旧 2024-08-21 03:55:59

您可以重写 ToString() 方法以包含您自己的自定义信息,并且仍然调用默认的基本 Exception ToString(),如下所示:

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

You can override the ToString() method to include your own custom information, and still call the default base Exception ToString() like this:

public class MyException : Exception
{
    public string CustomField { get; set; }
    public override string ToString()
    {
        return CustomField + Environment.NewLine + base.ToString();
    }
}
江南月 2024-08-21 03:55:59

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

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

If you're primarily looking at them in the debugger, then you can use the [DebuggerDisplay] attribute to specify their formatting and not touch the existing ToString method.

Otherwise, just overload ToString and be sure to call the base class version base.ToString()

宫墨修音 2024-08-21 03:55:59

最简单的方法

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

The simplest way

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();
}
み青杉依旧 2024-08-21 03:55:59

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

Inside the override call base.ToString() and modify the resulting string to your needs...

雄赳赳气昂昂 2024-08-21 03:55:59

Glinko的答案类似的想法是在基本字符串的第一行之后插入变量,但实现有点不同:

public override string ToString()
{
    string baseStr = base.ToString();
    return baseStr.Insert(baseStr.IndexOf('\n') + 1,
        string.Format("HttpStatusCode: {0}, TSError400: {1}\r\n",
        (int)HttpStatusCode,
        JsonConvert.SerializeObject(TSError400)));
}

Similar idea to Glinko's answer of insertion of your variables after the first line of base string, a bit different implementation:

public override string ToString()
{
    string baseStr = base.ToString();
    return baseStr.Insert(baseStr.IndexOf('\n') + 1,
        string.Format("HttpStatusCode: {0}, TSError400: {1}\r\n",
        (int)HttpStatusCode,
        JsonConvert.SerializeObject(TSError400)));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文