首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Exception.Message vs Exception.ToString()

Exception.Message vs Exception.ToString()
EN

Stack Overflow用户
提问于 2010-02-01 20:53:14
回答 8查看 138.8K关注 0票数 234

我有记录Exception.Message的代码。然而,我读到了一篇文章,它说使用Exception.ToString()更好。使用后者,您可以保留有关错误的更多关键信息。

这是真的吗?继续替换所有代码日志记录Exception.Message是否安全?

我还为log4net使用了基于XML的布局。Exception.ToString()是否可能包含无效的XML字符,从而导致问题?

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2010-02-01 20:55:46

Exception.Message仅包含与异常关联的消息(doh)。示例:

对象引用未设置为对象的实例

对于嵌套/内部异常,Exception.ToString()方法将提供更详细的输出,其中包含异常类型、消息(来自之前)、堆栈跟踪以及所有这些内容。更准确地说,该方法返回以下内容:

ToString返回当前异常的表示形式,以便于人类理解。如果异常包含区域性敏感数据,则ToString返回的字符串表示形式需要考虑当前系统区域性。虽然对返回字符串的格式没有确切的要求,但它应该尝试反映用户所感知的对象的值。

ToString的默认实现获取引发当前异常的类的名称、消息、对内部异常调用ToString的结果以及调用Environment.StackTrace的结果。如果这些成员中的任何一个为空引用(在Visual Basic中为Nothing),则其值不包括在返回的字符串中。

如果没有错误消息或者它是一个空字符串(""),则不会返回错误消息。仅当内部异常和堆栈跟踪的名称不是空值引用(在Visual Basic中为Nothing)时才返回它们。

票数 307
EN

Stack Overflow用户

发布于 2010-02-01 21:10:18

除了前面已经说过的以外,不要在异常对象上使用ToString()来显示给用户。只要Message属性就足够了,或者更高级别的自定义消息。

在日志记录方面,一定要在异常上使用ToString(),而不仅仅是Message属性,因为在大多数情况下,您会对此异常具体发生的位置以及调用堆栈是什么感到困惑。堆栈跟踪会告诉你所有这些。

票数 63
EN

Stack Overflow用户

发布于 2015-11-30 22:58:53

将整个异常转换为字符串

调用Exception.ToString()可以为您提供比仅使用Exception.Message属性更多的信息。然而,即使这样,仍然遗漏了许多信息,包括:

在添加到异常的所有其他自定义属性上找到的

  1. Data集合属性。

有时,您需要捕获这些额外的信息。下面的代码处理上述场景。它还以良好的顺序写出异常的属性。它使用的是C# 7,但如果需要的话,你应该可以很容易地转换到较旧的版本。另请参阅this相关答案。

代码语言:javascript
复制
public static class ExceptionExtensions
{
    public static string ToDetailedString(this Exception exception) =>
        ToDetailedString(exception, ExceptionOptions.Default);

    public static string ToDetailedString(this Exception exception, ExceptionOptions options)
    {
        if (exception == null)
        {
            throw new ArgumentNullException(nameof(exception));
        } 

        var stringBuilder = new StringBuilder();

        AppendValue(stringBuilder, "Type", exception.GetType().FullName, options);

        foreach (PropertyInfo property in exception
            .GetType()
            .GetProperties()
            .OrderByDescending(x => string.Equals(x.Name, nameof(exception.Message), StringComparison.Ordinal))
            .ThenByDescending(x => string.Equals(x.Name, nameof(exception.Source), StringComparison.Ordinal))
            .ThenBy(x => string.Equals(x.Name, nameof(exception.InnerException), StringComparison.Ordinal))
            .ThenBy(x => string.Equals(x.Name, nameof(AggregateException.InnerExceptions), StringComparison.Ordinal)))
        {
            var value = property.GetValue(exception, null);
            if (value == null && options.OmitNullProperties)
            {
                if (options.OmitNullProperties)
                {
                    continue;
                }
                else
                {
                    value = string.Empty;
                }
            }

            AppendValue(stringBuilder, property.Name, value, options);
        }

        return stringBuilder.ToString().TrimEnd('\r', '\n');
    }

    private static void AppendCollection(
        StringBuilder stringBuilder,
        string propertyName,
        IEnumerable collection,
        ExceptionOptions options)
        {
            stringBuilder.AppendLine($"{options.Indent}{propertyName} =");

            var innerOptions = new ExceptionOptions(options, options.CurrentIndentLevel + 1);

            var i = 0;
            foreach (var item in collection)
            {
                var innerPropertyName = $"[{i}]";

                if (item is Exception)
                {
                    var innerException = (Exception)item;
                    AppendException(
                        stringBuilder,
                        innerPropertyName,
                        innerException,
                        innerOptions);
                }
                else
                {
                    AppendValue(
                        stringBuilder,
                        innerPropertyName,
                        item,
                        innerOptions);
                }

                ++i;
            }
        }

    private static void AppendException(
        StringBuilder stringBuilder,
        string propertyName,
        Exception exception,
        ExceptionOptions options)
    {
        var innerExceptionString = ToDetailedString(
            exception, 
            new ExceptionOptions(options, options.CurrentIndentLevel + 1));

        stringBuilder.AppendLine($"{options.Indent}{propertyName} =");
        stringBuilder.AppendLine(innerExceptionString);
    }

    private static string IndentString(string value, ExceptionOptions options)
    {
        return value.Replace(Environment.NewLine, Environment.NewLine + options.Indent);
    }

    private static void AppendValue(
        StringBuilder stringBuilder,
        string propertyName,
        object value,
        ExceptionOptions options)
    {
        if (value is DictionaryEntry)
        {
            DictionaryEntry dictionaryEntry = (DictionaryEntry)value;
            stringBuilder.AppendLine($"{options.Indent}{propertyName} = {dictionaryEntry.Key} : {dictionaryEntry.Value}");
        }
        else if (value is Exception)
        {
            var innerException = (Exception)value;
            AppendException(
                stringBuilder,
                propertyName,
                innerException,
                options);
        }
        else if (value is IEnumerable && !(value is string))
        {
            var collection = (IEnumerable)value;
            if (collection.GetEnumerator().MoveNext())
            {
                AppendCollection(
                    stringBuilder,
                    propertyName,
                    collection,
                    options);
            }
        }
        else
        {
            stringBuilder.AppendLine($"{options.Indent}{propertyName} = {value}");
        }
    }
}

public struct ExceptionOptions
{
    public static readonly ExceptionOptions Default = new ExceptionOptions()
    {
        CurrentIndentLevel = 0,
        IndentSpaces = 4,
        OmitNullProperties = true
    };

    internal ExceptionOptions(ExceptionOptions options, int currentIndent)
    {
        this.CurrentIndentLevel = currentIndent;
        this.IndentSpaces = options.IndentSpaces;
        this.OmitNullProperties = options.OmitNullProperties;
    }

    internal string Indent { get { return new string(' ', this.IndentSpaces * this.CurrentIndentLevel); } }

    internal int CurrentIndentLevel { get; set; }

    public int IndentSpaces { get; set; }

    public bool OmitNullProperties { get; set; }
}

顶级提示-记录异常

大多数人将使用此代码进行日志记录。考虑对我的Serilog.Exceptions NuGet包使用Serilog,它也会记录异常的所有属性,但在大多数情况下会更快,而且没有反射。Serilog是一个非常高级的日志记录框架,在写这篇文章的时候非常流行。

顶级技巧-人类可读的堆栈跟踪

您可以使用Ben.Demystifier NuGet包来获取异常的人类可读堆栈跟踪,如果您使用的是Serilog,则可以使用serilog-enrichers-demystify NuGet包。

票数 32
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2176707

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档