如何处理导致异常的WinRT异常



如果Windows运行时类型引发COM错误,.NET似乎经常(或总是?)将此错误封装到Exception实例中。错误消息包括COM HRESULT错误代码。例如,将新的Cryptographic API与AES-CBC一起使用时,错误的缓冲区长度会导致Exception显示消息"提供的用户缓冲区对请求的操作无效。(Exception from HRESULT: 0x800706F8)"。

那么,我们应该如何处理这些例外情况呢?我们应该从异常中读取HRESULT代码来了解这是什么类型的异常吗?在经典的.NET中,我会得到一个CryptographicException,可以用来区分加密错误和其他错误。

另一件我不理解的事情是,Microsoft代码质量规则规定永远不应该抛出Exception,而应该始终抛出派生类型。原因是不应该强迫任何人捕获一般的Exception,它也捕获像OutOfMemoryException这样的更致命的异常。另一条规则是,人们永远不应该在图书馆里抓到Exception。如果我们被迫在Windows应用商店应用程序或WinRT库中捕获Exception,我们如何遵循这些策略?

顺便说一句:Clemens Vasters在他的博客中展示了我们如何在避免捕捉致命异常的同时捕捉异常。我认为捕获Exception不再是坏代码。

可以捕获Exception,通过打开HRESULT来处理特定错误,如果错误是"意外的",则重新抛出Exception。例如,

try
{
// ...
}
catch (Exception ex)
{
switch (ex->HResult)
{
case E_INVALID_USER_BUFFER: // 0x800706f8
// handle invalid buffer case...
break;
default:
// Unexpected exception; re-throw:
throw;
}
}

(我要注意的是,提供一个无效的缓冲区听起来更像是一个逻辑错误,而不是运行时错误,所以我想知道这个特定的异常是否真的应该被捕获。)

或者,一个更通用的解决方案是编写一个函数或一组函数,为已知的HRESULT处理Exception,并重新抛出一个更具体的异常。例如,

static void HandleKnownExceptions(Action f)
{
try
{
f();
}
catch (Exception ex)
{
// Detect expected HRESULTs and throw the more-specific exception
// type for each.
}
}

这两种方法在C++和C#中都同样有效。

请注意,Exception不一定是由平台或其他组件直接抛出的。在Windows Runtime ABI层,没有例外:所有错误都由HRESULT跨ABI边界报告。CLR将少数已知的HRESULT转换为更具体的异常类型,但不能执行一般的转换。

最新更新