从 ArgumentException 中获取原始错误消息

Getting the original error message out of an ArgumentException

在写.Net内部处理的classes时,我经常用ArgumentException表示给定的数据有问题,无法处理。由于程序的性质,我放在这些例外中的文本有时与用户相关,因此它经常显示在 UI.

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

当然,我可以使用我自己的例外 class,但是由于这些方法中有很多是用于压缩和解压缩旧 DOS 游戏中的专有文件格式,我希望这些方法都被记录下来在 wiki 上并且通常可以被其他任何人轻松使用,我更愿意保持它们的便携性并避免依赖其他外部 classes。而且,作为旁注,subclassing 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;
    }
}

(from referencesource.microsoft.com)

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

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

因为我不想深入研究反射,所以我想出了一种获取原始数据但没有关联 class 行为的好方法,那就是将其序列化。序列化信息中的属性名称非常简单,无需 ArgumentException getter 自行添加即可访问。

完成此任务的代码非常简单:

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