代码之家  ›  专栏  ›  技术社区  ›  Noldorin

正在引发Win32Exception

  •  18
  • Noldorin  · 技术社区  · 16 年前

    我最近写了很多代码,涉及到与Win32 API的互操作,并且开始想知道如何最好地处理由调用Windows API函数引起的本机(非托管)错误。

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

    // 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();
    

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

    throw new Win32Exception(Marshal.GetLastWin32Error());
    

    现在,这一切都很好,因为它抛出了一个异常,该异常适当地包含设置的Win32错误代码以及(通常)人类可读的错误描述 Message

    1. 在构造函数中为指定自定义错误消息 Win32Exception .

      throw new Win32Exception(Marshal.GetLastWin32Error(), "My custom error message.");
      
    2. Win32异常 在另一个异常对象中,以便保留原始错误代码和消息( Win32异常 现在是 InnerException 父异常的一部分)。

      throw new Exception("My custom error message.", Win32Exception(Marshal.GetLastWin32Error()));
      
    3. 与2相同,但使用另一个 Win32异常 作为包装器异常。

    4. 与2相同,只是使用从 Exception 作为包装器异常。

    5. 与2相同,只是在批准时使用BCL(基类库)异常作为父异常。甚至不确定是否适合设置 内部异常 在这种情况下(可能是对于低级包装器,而不是更高级/抽象的接口,它不会使Win32 interop在幕后发生变得明显?)

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

    3 回复  |  直到 16 年前
        1
  •  4
  •   Daniel Earwicker    16 年前

    这实际上并不特定于Win32异常;问题是,什么时候两个不同的错误案例应该由两个不同的异常派生类型标识,什么时候它们应该抛出同一个类型并在其中存储不同的值?

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

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

        2
  •  3
  •   Reed Copsey    16 年前

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

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

    不过,总的来说,我会避免您列出的选项2和选项3。

    选项二抛出了一种通用的异常类型——我非常建议完全避免这种情况。将一个特定的异常包装成一个更一般化的异常似乎是不合理的。

        3
  •  2
  •   Keltex    16 年前

    就我个人而言,我会做2或4次……最好是4次。将Win32Exception包装在上下文敏感的异常中。这样地:

    void ReadFile()
    {
        if (!WinApi.NativeFunction(param1, param2, param3))
            throw MyReadFileException("Couldn't read file", new Win32Exception());
    }
    

    推荐文章