为什么这个万能的块没有实际上捕获所有内容

7
代码非常简单——问题在于groupPath字符串中存在一个无效字符(确切地说是“/”)。
我试图做的事情(至少作为一个临时措施)是跳过我无法获取cn的DirectoryEntries,无论原因如何。
然而,当我运行这段代码时,catch块没有运行,我得到了以下结果: 服务器不可用,并出现未处理的System.Runtime.InteropServices.COMException异常。
为什么catch块没有捕获这个异常?
try
{
    using (DirectoryEntry groupBinding = new DirectoryEntry("LDAP://" + groupPath))
    {
        using (DirectorySearcher groupSearch = new DirectorySearcher(groupBinding))
        {

            using (DirectoryEntry groupEntry = groupSearch.FindOne().GetDirectoryEntry())
            {
                results.Add(string.Format("{0}", groupEntry.Properties["cn"].Value.ToString()));
            }
        }
    }
}
catch
{
    Logger.Error("User has bad roles");
}

额外观察: 实际上这段代码在一个自定义的RoleProvider中,有趣的是,如果我在一个简单的winforms应用程序中引用这个提供程序,并使用相同的输入调用这个方法,catch块会按照预期执行。我认为这表明,关于.NET异常与COM异常的提出的答案是不准确的。 虽然我不明白为什么这段代码在从WebDev服务器执行时无法捕获


4
在调试器中,还是在构建中? - Tom Anderson
你在哪一行代码上遇到了异常?以及是哪个线程引起的? - lc.
2
另外,你能加上异常吗?(Exception.ToString()) - Tom Anderson
我在想,也许异常是在包装Using语句产生的Dispose的隐式Finally块中抛出的?Finally块内部不是有一些奇怪的异常处理规则吗?无论如何,以防万一是这种情况,我会将Using语句提取出来,手动编写代码,以更好地掌握异常发生的确切位置。 - ewbi
你不是在发布模式下调试,对吧?否则会发生奇怪的事情。 - Mez
5个回答

13

如果没有指定要捕获什么异常,它会默认为.NET异常。你的异常是在COM中发生的,在这里.NET尚未设置以捕获该异常。处理这种情况的最佳方式是捕获COM异常,应该像这样:

    try
    {

    }
    catch (System.Runtime.InteropServices.COMException COMex)
    {

    }
    catch (System.Exception ex)
    {

    }

COMException可能继承自System.Exception,但在与System.Exception的COM互操作中仍然无法捕获。我已经做了很多与AutoCAD的互操作,并且这让我疯狂了一段时间,因为我习惯于使用catch all而不是指定我的确切异常。 - Noah
如果Noah使用catch (Exception ex) {...},那么它会捕获COMException吗?根据您的经验呢?即,当您不指定任何异常类型时才会出现奇怪的情况,还是除非您明确指定COMException,否则总是会发生这种情况? - Rory
你能指出更多关于这个话题的讨论或例子吗?我非常感兴趣。谢谢。 - Rory
好吧,看起来微软对此相当模糊,但是它的最佳实践(http://msdn.microsoft.com/en-us/library/seyhszts.aspx)表明您应该尝试捕获将被抛出的确切异常...个人而言,我只在处理COM时使用Interop异常,否则我只使用通用的System.Exception或根本不使用。 - Noah
这也可能在描述整个异常处理过程时有所帮助。http://msdn.microsoft.com/en-us/library/6kzk0czb.aspx - Noah
显示剩余7条评论

3
有三个原因:
  1. 运行时存在错误
  2. 应用程序和/或线程在执行某些代码的过程中结束
  3. 你没有看到整个情况
就我个人而言,我倾向于第三种情况。我经历了无数次调试会话,其中我想知道为什么某段代码不能处理我的异常,实际上是Visual Studio配置为停止所有抛出的异常,无论它们是否被捕获。
你是否尝试过在调试器中要求程序继续运行,并查看是否最终进入catch块?
此外,请检查Visual Studio中的设置,转到“调试->异常”对话框,并检查是否选中了任何“抛出”的复选框。如果有的话,那可能是你的问题。
当然,如果你在运行时看到这个问题,没有调试器附加,那么除了上面提到的第1和第2点之外,我就不知道了。
当然还有第4点:未知。

2

在try块内抛出的COMException将被catch块捕获并忽略。

休息一下,喝杯咖啡,在"Logger.Error..."这行设置一个断点,然后再试一次。


2

除了COMException之外,还有一些异步异常是无法捕获的,例如:

  • OutOfMemoryException
  • StackoverflowException(不,这不是与本网站相关的玩笑 :)
  • ThreadAbortException

你确定这不是这种情况吗?


1
FYI,你可以捕获OutOfMemoryException。是否能够成功释放一些内存(释放对事物的引用)取决于你的应用程序。 - Curt Nichols
是的,技术上你可以捕捉到它们,但一旦你退出catch块,CLR运行时会一遍又一遍地重新抛出它们。 - Andrei Rînea

1

我曾经遇到过类似的问题。我调用了一个VB6 COM对象,结果出现了错误。实际上,异常类型是System.Reflection.TargetInvocationException。内部异常被设置为COMException。最终,我捕获了System.Reflection.TargetInvocationException并检查了innerException。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接