首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >抛出Win32Exception

抛出Win32Exception
EN

Stack Overflow用户
提问于 2009-03-23 15:57:53
回答 3查看 11K关注 0票数 19

我最近编写了很多涉及到与Win32 API进行互操作的代码,并且开始想知道处理由调用Windows API函数引起的本机(非托管)错误的最佳方法是什么。

目前,对本机函数的调用如下所示:

代码语言:javascript
复制
// NativeFunction returns true when successful and false when an error
// occurred. When an error occurs, the MSDN docs usually tell you that the
// error code can be discovered by calling GetLastError (as long as the
// SetLastError flag has been set in the DllImport attribute).
// Marshal.GetLastWin32Error is the equivalent managed function, it seems.
if (!WinApi.NativeFunction(param1, param2, param3))
    throw new Win32Exception();

引发异常的代码行可以被等效地重写,我相信:

代码语言:javascript
复制
throw new Win32Exception(Marshal.GetLastWin32Error());

现在,这一切都很好,因为它适当地抛出了一个异常,其中包含已设置的Win32错误代码,以及(通常)人类可读的错误描述作为异常对象的Message属性。然而,我一直在想,如果不是全部,至少修改/包装这些异常中的一些是明智的,以便它们给出稍微更面向上下文的错误消息,即在使用本机代码的任何情况下都更有意义。为此,我考虑了几种替代方案:

Win32Exception的构造函数中指定自定义错误消息的

抛出新的Win32Exception(Marshal.GetLastWin32Error() ),"My custom error message.");

  • Wrapping the Win32Exception in the Exception object,以便保留原始错误代码和消息( Win32Exception现在是父异常的InnerException )。

抛出新的异常(“我的自定义错误消息。”,Win32Exception(Marshal.GetLastWin32Error()));

  • The与2相同,除了使用另一个类库作为与2相同的包装器exception.

  • The之外,除了使用从Exception派生的自定义类作为与2相同的包装器exception.

  • The之外,除了在适当的时候使用BCL (基类库)异常作为父类。不确定在这种情况下将InnerException设置为Win32Exception是否合适(可能对于低级包装器,而不是高级/抽象接口,它不会明显地表明Win32互操作是在幕后发生的?)

本质上,我想知道的是:在.NET中处理Win32错误的推荐实践是什么?我看到它在开源代码中以各种不同的方式完成,但我很好奇是否有任何设计指南。如果没有,我会对你的个人喜好感兴趣。(也许您甚至都不使用上述方法?)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-03-23 16:10:11

这并不是Win32异常所特有的;问题是,何时应该由两个不同的异常派生类型来标识两种不同的错误情况,以及它们何时应该抛出内部存储了不同值的相同类型?

不幸的是,如果事先不知道你的代码将被调用的所有情况,这是不可能回答的。:)这是只能按类型过滤异常的问题。从广义上讲,如果您强烈认为以不同的方式处理两个错误案例会很有用,那么就抛出不同的类型。

否则,通常只需要将Exception.Message返回的字符串记录或显示给用户即可。

如果有其他信息,请用您自己的更高级别的内容包装Win32Exception。例如,您正在尝试对一个文件执行某些操作,而您在其下运行的用户没有权限执行此操作。捕获Win32Exception,将其包装在您自己的异常类中,该类的消息提供文件名和正在尝试的操作,后跟内部异常的消息。

票数 4
EN

Stack Overflow用户

发布于 2009-03-23 16:18:24

我的观点一直是,处理这一问题的适当方式取决于目标受众以及如何使用您的类。

如果你的类/方法的调用者要意识到他们正在以某种形式调用Win32,我会使用你指定的选项1)。对我来说,这似乎是最“清楚”的。(但是,如果是这样的话,我会以一种明确的方式命名您的类,以表明将直接使用Win32应用程序接口)。这就是说,在BCL中有一些异常,为了更清楚地说,它们实际上是Win32Exception的子类,而不仅仅是包装它。例如,SocketException派生自Win32Exception。我个人从来没有使用过这种方法,但它看起来确实是一种潜在的干净的方式来处理这个问题。

如果您的类的调用者不知道您正在直接调用Win32应用程序接口,我将处理异常,并使用您定义的自定义的、更具描述性的异常。例如,如果我正在使用您的类,并且没有迹象表明您正在使用Win32 api (因为您在内部使用它是出于某种特定的、不明显的原因),那么我就没有理由怀疑我可能需要处理Win32Exception。您可以始终记录这一点,但对我来说,捕获它并给出一个在您的特定业务上下文中更有意义的异常似乎更合理。在这种情况下,我可能会将初始Win32Exception包装为内部异常(即:您的案例4),但根据导致内部异常的原因,我可能不会。

此外,在很多情况下,Win32Exception会从本机调用中抛出,但BCL中还有其他更相关的异常。当您调用未包装的原生API时就是这种情况,但是在BCL中包装了类似的函数。在这种情况下,我可能会捕获异常,确保它是我所期望的,然后抛出标准的BCL异常。一个很好的例子就是使用SecurityException而不是抛出Win32Exception。

不过,一般来说,我会避免你列出的选项2和3。

选项二抛出了一个通用的异常类型--我强烈建议完全避免它。将特定的异常包装成更通用的异常似乎是不合理的。

第三种选择似乎是多余的--与第一种选择相比,实际上没有什么优势。

票数 3
EN

Stack Overflow用户

发布于 2009-03-23 16:18:37

就我个人而言,我会做#2或#4...Preferably #4。将Win32Exception包装在你的异常中,这是上下文敏感的。如下所示:

代码语言:javascript
复制
void ReadFile()
{
    if (!WinApi.NativeFunction(param1, param2, param3))
        throw MyReadFileException("Couldn't read file", new Win32Exception());
}

这样,如果有人捕捉到异常,他们就会很好地知道问题发生在哪里。我不会做#1,因为它需要catch来解释你的文本错误消息。#3实际上并没有给出任何额外的信息。

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

https://stackoverflow.com/questions/673956

复制
相关文章

相似问题

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