取消

Exception.Data 为异常添加更多调试信息

我们抛出异常是为了知道程序中目前的状态发生了错误。为了能够知道错误的详细信息便于我们将来避免产生这样的错误,我们会选用合适的异常类型,在异常中编写易于理解的 message 信息。但是有时我们需要更多的信息进行调试才能帮忙在将来避免这个异常。


System.Exception 类中就自带了这样的属性 Data,它是 IDictionary 类型的:

1
2
3
4
5
6
7
8
9
10
11
12
public virtual IDictionary Data { 
    [System.Security.SecuritySafeCritical]  // auto-generated
    get {
        if (_data == null)
            if (IsImmutableAgileException(this))
                _data = new EmptyReadOnlyDictionaryInternal();
            else
                _data = new ListDictionaryInternal();
        
        return _data;
    }
}

别问我为什么把括号放最右边,那是微软自己写的源码 点击这里查看

最近在调试 .NET Framework 内部代码的异常时就发现微软就是使用这个属性储存异常的更多细节的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
internal void RegisterStylusDeviceCore(StylusDevice stylusDevice)
{
    lock (__stylusDeviceLock)
    {
        int stylusDeviceId = stylusDevice.Id;
        // The map must contain unique entries for each stylus device.
        if (__stylusDeviceMap.ContainsKey(stylusDeviceId))
        {
            InvalidOperationException ioe = new InvalidOperationException();
            // We add a tag here so we can check for this specific exception
            // in TabletCollection when adding new tablet devices.
            ioe.Data.Add("System.Windows.Input.StylusLogic", "");
            throw(ioe);
        }
        __stylusDeviceMap[stylusDeviceId] = stylusDevice;
    }
}

以上代码出自 .NET Framework 4.6 的 System.Windows.Input.StylusLogic 类型,https://referencesource.microsoft.com 里 .NET Framework 4.7 中找不到。

需要注意的是,ExceptionToString() 方法并不会把这个字典转成字符串的任意一个部分;所以,如果需要在日志中记录程序中全局捕获的异常,需要自己去遍历异常中的 Data 的每一项。不过,为了解决掉更多的程序错误,我们记录日志的时候不已经写了更多的信息(比如 InnerException)了吗?

本文会经常更新,请阅读原文: https://blog.walterlv.com/dotnet/2017/09/12/exception-data.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected])

登录 GitHub 账号进行评论