首页 > 解决方案 > 从 ArgumentException 中获取原始错误消息

问题描述

在.Net 中编写用于内部处理的类时,我经常用它ArgumentException来表示给定数据有问题并且无法处理。由于程序的性质,我在这些异常中输入的文本有时与用户相关,因此它经常显示在 UI 上。

但是,我注意到它ArgumentException专门覆盖了Message属性以附加它自己的字符串来指示哪个参数导致了异常。我不希望这个额外的文本污染消息,因为实际的参数名称是内部处理信息,实际上不需要向用户显示,而且它添加了一个换行符,而且它是本地化的,一团糟设置我在 UI 上显示的消息的格式。解决这个问题的唯一方法是不给异常提供实际的参数名称,但我也不想通过删除该信息来破坏我自己的调试/日志记录。

当然,我可以使用我自己的异常类,但由于这些方法中有很多是用于压缩和解压缩旧 DOS 游戏中的专有文件格式,我希望这些方法都记录在 wiki 上,并且通常易于使用其他任何人,我宁愿保持它们的可移植性并避免依赖其他外部类。而且,作为旁注,子类ArgumentException化当然会产生同样的问题。

原始来源:

public override String Message
{
    get {
        String s = base.Message;
        if (!String.IsNullOrEmpty(m_paramName)) {
            String resourceString = Environment.GetResourceString("Arg_ParamName_Name", m_paramName);
            return s + Environment.NewLine + resourceString;
        }
        else
            return s;
    }
}

来自referencesource.microsoft.com

由于这实际上覆盖了该Message属性,因此似乎没有正常的方法可以获取内部存储的真实消息。根据本地化差异(并且我给它的消息可能已经有换行符),在换行符处拆分似乎很混乱并且可能不可靠,并且为此使用反射似乎相当混乱。有没有一种干净的方法来恢复原始消息?

(出于记录原因,在此处发布此解决方案,因为当我遇到这种行为时,我真的很沮丧)

标签: c#.netexceptionargumentexception

解决方案


因为我不想深入研究反射,所以我想出一个在没有相关类行为的情况下获取原始数据的好方法是序列化它。序列化信息中的属性名称非常简单,可以在没有ArgumentExceptiongetter 自己添加的情况下对其进行访问。

实现这一点的代码非常简单:

public static String RecoverArgExceptionMessage(ArgumentException argex)
{
    if (argex == null)
        return null;
    SerializationInfo info = new SerializationInfo(typeof(ArgumentException), new FormatterConverter());
    argex.GetObjectData(info, new StreamingContext(StreamingContextStates.Clone));
    return info.GetString("Message");
}

推荐阅读