【问题标题】:How to Determine Exception Subtype如何确定异常子类型
【发布时间】:2018-01-17 11:35:07
【问题描述】:

我想知道是否有确定异常子类型的标准方法。例如,对于File.Copy() 方法,IOException 表示目标文件存在发生了一般 I/O 错误。还有其他类似的情况。在我的异常处理程序中,我如何确定它是哪个?我正在检查ex.Message 的末尾是否有字符串already exists.,它有效,但看起来非常笨拙且不可靠。

虽然可以在目标文件上检查File.Exists(),但如果存在,请与用户确认覆盖,然后执行File.Copy(),这不是原子的,也就是说,在检查和复制之间,可以要更改的条件,例如,如果某个其他进程创建或将文件复制到目标位置。

编辑: 我这里已经根据 cmets 改过代码了,不过我只是回滚了,就贴在这里,只是为了说明我在做什么:

        Try
            File.Copy(SrcFile, DstFile, OverWrite)

        Catch ex As DirectoryNotFoundException
            MsgBox(ex.Message)

        Catch ex As FileNotFoundException
            MsgBox("File not found: " & ex.FileName)

        Catch ex As UnauthorizedAccessException
            MsgBox("You do not have write access to the destination.")

        Catch ex As IOException
            ' IOException represents an existing destination file OR a general IO error.
            If SubStr(ex.Message, -15) = "already exists." Then
                OverwriteCheck = MsgBox(
                "Overwrite " & IO.Path.GetFileName(SrcFile) & " in destination directory?",
                MsgBoxStyle.YesNo
                )
                If OverwriteCheck = DialogResult.Yes Then
                    Try
                        File.Copy(SrcFile, DstFile, OverWrite)
                    Catch iex As Exception
                        MsgBox("Unable to copy " & SrcFile & ":" & vbNewLine & iex.Message)
                    End Try
                End If
            Else
                Throw ex
            End If

        Catch ex As ArgumentException
            ' The user left a blank line in the text box. Just skip it.
        End Try

【问题讨论】:

  • 在您的具体情况下,您应该检查 destFileName 是否存在并且覆盖是否为 false
  • OK,先用File.Exists()直接检查,而不是依赖异常?我想我必须这样做。
  • 如果可以避免异常,则永远不要将其作为程序逻辑的一部分。
  • 啊,我明白了。谢谢你。如果你觉得值得,你能把这一切都放在一个答案中吗?
  • @djv 我只是想到了一些东西:File.Exists() -> File.Copy() 不是原子的。嗯,我猜够近了。

标签: vb.net exception-handling


【解决方案1】:

我相信您正在寻找这种模式:

Try
    IO.File.Copy("source", "Dest", True)

Catch exUnAuth As System.UnauthorizedAccessException

Catch exArg As System.ArgumentException

Catch exNotFound As IO.FileNotFoundException

Catch exGeneral As System.Exception

End Try

将特定异常列表放在序列的首位。最后一个测试的异常应该是最少派生的。

您应该通读文档:How to use structured exception handling in Visual Basic .NET or in Visual Basic 2005。是的,这是一个旧的参考,但这表明它已经成为语言的一部分。

【讨论】:

  • 谢谢,但这不是如何处理异常的问题,而是一些异常代表不止一种可能情况的事实。事实上,我确实有我的异常处理程序,但IOException 是模棱两可的,即使我先检查派生异常也是如此。
  • @alanlittle,所以您的问题不是关于在讨论 .Net 类型系统时通常使用的术语确定异常类型,而是在特定异常不存在/或时从异常消息中提取含义没有被抛出。
  • 好吧,文档说IOException 代表一个现有的目标文件或一个 I/O 错误。即使在检查了源自IOException 的异常之后,这种歧义仍然存在。但是,请参阅上面的 djv 的 cmets;我应该先检查现有文件,而不是依赖异常。
  • @alanlittle,虽然在调用 Copy 方法之前检查文件是否存在似乎是一个可靠的想法,但如果其他进程删除了您的代码检查点之间的文件,它仍然会失败它和Copy 尝试打开文件。这种情况在您的特定用例中可能不存在,但请注意,在其他情况下确实会发生。
  • 是的,这就是我意识到的:操作不是原子的,特别是因为如果文件存在,我需要与用户确认覆盖。请参阅上面我对 djv 的评论。但是,正如您所说,在这种情况下可能不是问题。谢谢。
【解决方案2】:

这是一个使用 FileStreams 获取有关您的异常的更详细信息的选项

Sub Main()
    Try
        copyTo("C:\t\output3.txt", "C:\t\output1.txt", True)
    Catch ex As Exception
        Console.WriteLine(ex.Message)
    End Try
    Console.ReadLine()
End Sub

Private Sub copyTo(source As String, destination As String, Optional overwrite As Boolean = False)
   ' raises FileNotFoundException if source doesn't exist
    Using fsSource As New FileStream(source, FileMode.Open, FileAccess.Read, FileShare.None)
        If Not overwrite AndAlso File.Exists(destination) Then
            ' Raises exception when destination file exists and not overwrite
            Throw New Exception(
                String.Format("Destination file '{0}' exists and overwrite is false.", destination))
        Else
            Using fsDestination As New FileStream(destination, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)
                fsSource.CopyTo(fsDestination)
            End Using
        End If
    End Using
End Sub

这是一个基本示例,但您可以了解如何区分不同的异常情况,同时在检查文件存在和复制之间具有原子性。

【讨论】:

  • +1 是一种很好的通用方法。现在,如果 OP 将他的问题编辑为关于这个特定问题,以便其他人可以找到它。至少在 Windows 上,另一种选择是检查 System.Runtime.InteropServices.Marshal.GetLastWin32Error 并创建查找。
  • 优秀。谢谢。
猜你喜欢
  • 2010-10-08
  • 2014-01-23
  • 2011-01-03
  • 1970-01-01
  • 1970-01-01
  • 2021-01-06
  • 2012-02-12
  • 2010-11-02
  • 2012-08-30
相关资源
最近更新 更多