【问题标题】:C# unable to catch all exceptionsC# 无法捕获所有异常
【发布时间】:2015-06-26 06:02:11
【问题描述】:

我正在编写一个 C# 应用程序(在 Linux 中使用单声道但没关系),并且我正在使用 duplicati dll 进行编程。我希望程序永远不会崩溃,所以我试图捕获每个异常。现在的问题是抛出了异常,我无法捕获它。也许来自一个线程?!?

旁注:仅出于测试目的,我故意尝试备份到我没有权限的位置。如果我给予许可,则不会出错。

代码如下:

try {
    Interface i = new Interface(backend, options);
    result = i.Backup(folders.ToArray());
} catch (Exception e) {
    //Write to log.
    //Here is no throw; !!
}

我得到以下堆栈跟踪:

Error : System.Exception: Failed to retrieve file listing: Access to the path "/home/pi/test" is denied. ---> System.UnauthorizedAccessException: Access to the path "/home/pi/test" is denied.
  at System.IO.Directory.GetFileSystemEntries (System.String path, System.String searchPattern, FileAttributes mask, FileAttributes attrs) [0x00000] in <filename unknown>:0
  at System.IO.Directory.GetFiles (System.String path, System.String searchPattern) [0x00000] in <filename unknown>:0
  at System.IO.Directory.GetFiles (System.String path) [0x00000] in <filename unknown>:0
  at Duplicati.Library.Backend.File.List () [0x00000] in <filename unknown>:0
  at Duplicati.Library.Main.BackendWrapper.ListInternal () [0x00000] in <filename unknown>:0
  --- End of inner exception stack trace ---
  at Duplicati.Library.Main.BackendWrapper.ListInternal () [0x00000] in <filename unknown>:0
  at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&)
  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0

为什么我无法捕获所有异常?我是不是做错了什么?

【问题讨论】:

  • 不直接相关:一些异常比其他异常更异常 - 比如 StackOverflow... 回到问题 - 堆栈与显示的代码并不真正对应 - 很难提出任何建议,但确实抛出了异常其他线程上的代码不会被该代码捕获。
  • 报错是哪一行?
  • 并非所有异常都是可恢复的。假设发生此异常,它会中断您的代码并转到处理程序。你的程序应该在哪里恢复?
  • @AlexeiLenenkov:好的,谢谢,我明白了!但是在这里它不能是堆栈,因为当我设置正确的权限时我的程序可以工作。那么有没有可能阻止这样的程序崩溃?!?
  • @FahadJameel:这就是问题所在,我看不到它,因为堆栈跟踪中没有任何内容,但这些行是对库的唯一调用,所以它必须在那里

标签: c# exception exception-handling mono try-catch


【解决方案1】:
Error : System.Exception: Failed to retrieve file listing: Access to the path...

嗯,这是一个托管异常,你应该能够捕捉到它,期间。 Duplicati 正在使用 Interop 到本机库,该调用中的失败是调用堆栈存在的地方,但它正在展开并通过托管调用堆栈传播。

我写了一个非常快速的 Duplicati 示例,它捕获了所有异常...

也不例外:

mono HelloDup.exe "/tmp"
File: Local folder or drive

捕捉到异常:

ls /home/private/privateinfo
ls: : Permission denied
mono HelloDup.exe "/home/private/privateinfo"
Exception: Access to the path "/home/private/privateinfo" is denied.: Type:System.UnauthorizedAccessException

捕捉到异常:

mono HelloDup.exe "/foobar"
Exception: The folder /foobar does not exist: Type:Duplicati.Library.Interface.FolderMissingException

捕捉到异常:

ls -l /noperms/private.txt
--w-------  1 root  wheel  0 Jun 25 14:16 /noperms/private.txt
mono HelloDup.exe "/noperms/private.txt"
Exception: The folder /noperms/private.txt does not exist: Type:Duplicati.Library.Interface.FolderMissingException

代码示例:

try {
    var file = new Duplicati.Library.Backend.File(args[0], options);
    file.CreateFolder();
    Console.WriteLine ("File: {0}", file.DisplayName);
} catch (Exception e) {
    Console.WriteLine ("Exception: {0}: Type:{1}", e.Message, e.GetType());
}

后续步骤:

我会检查您正在使用的 Mono 和 Duplicati 的版本...如果您是 Mono 的基本系统安装,那么您可能真的落后于时代。我还使用 xbuild 编译 Duplicati,所以我使用的是 GitHub 主分支的 HEAD。

【讨论】:

  • 感谢您的回答!当我复制您的确切代码示例并更改文件夹的路径时,我也能够捕获异常!但不是当我使用接口类时。我想这里的区别在于,使用Backend.File 会直接捕获异常,但是使用Interface 时会在另一个线程中抛出异常。
  • 有趣。您使用的是哪个版本的单声道? (单--版本),还有哪个架构? x86 还是 amd64/x86_64?此外,对 C 与 C++ 的互操作调用将导致不同的异常处理,因为 C 没有异常处理,而 C++ 可以,但它与托管异常不同......它很快就会变得棘手;-)
  • 我使用的是单声道版本 3.2.8。我的架构是 ARMv6 (Raspberry :-)) 也许这就是问题所在!是的,变得非常棘手......
【解决方案2】:

catch 块可能会引发异常

无论如何,@gunr2171 想法的变体 - 创建一个单独的 Vis。具有单个文件(类)的 Studio 项目,它所做的只是调用包装在 try/catch 中的主程序;所以它位于应用程序的最顶部。

如果你的库是线程化的,它应该暴露一些东西来测试线程异常;很像BackgroundWorker.RunWorkerCompleted event


注册 AppDomain.UnhandledException 事件

A simple tutorial


有价值的异常捕获

充分利用Exception.Data 属性。有时我会在我的课程中明确覆盖ToString(),以便将其放入Exception.Data

在应用程序主体中尽可能缩小范围(OP 似乎已经这样做了)。此上下文将帮助您在Exception.Data 中捕获特别相关的信息。阅读库的 - 和 .NET - 文档。

在应用程序顶部有一个通用的try/catch

避免不添加上下文的重新捕获层。

重新投掷:throw e 将堆栈跟踪丢弃到该点。 throw 代替。


让您的应用程序健壮

  • 定义默认状态。 The null object pattern
  • 强制客户端使用您的构造函数。不要公开属性并期望客户端正确初始化。 Alan Kay 强调公开属性(状态)不是面向对象的编程。
  • 我讨厌null 字符串。这是我最喜欢的实时生产代码:if(string.IsNullOrEmpty(myString.Trim()))

一些希望有帮助的链接

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-29
    • 1970-01-01
    • 2018-11-01
    相关资源
    最近更新 更多