8

我对 VS2010 有一个问题,调试器因未处理的异常而停止。但是,肯定会处理异常。事实上,如果我将代码放在 catch 块中,我会在按 F5 时点击它。在 Debug -> Exceptions 中,我绝对没有选中“Thrown”复选框,因此 IMO 绝对没有理由弹出未处理的异常对话框......

我无法发布确切的代码,但很快就会制作一个示例。有问题的代码部分背后的基本思想是我有一个与硬件对话的线程,如果与它对话时出错,那么我会抛出一个HardwareException. 线程是用 启动的BeginInvoke,当我调用EndInvoke.

当在调试器中抛出异常时,我收到一个消息框,上面写着“用户代码未处理硬件异常”。但它是!!!

编辑——嗯,这让我发疯了。我的示例代码代表了我的应用程序中的代码,它看起来像这样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Threading;

namespace ConsoleApplication1
{
    public class HardwareException : ApplicationException
    {
        public HardwareException( string message) : base(message) {}
    }

    class Program
    {
        delegate void HardwareTestDelegate();

        static void Main(string[] args)
        {
            HardwareTestDelegate d = new HardwareTestDelegate( HardwareTestThread);
            d.BeginInvoke( HardwareTestComplete, null);
            while( true);
        }

        static void HardwareTestThread()
        {
            throw new HardwareException( "this is a test");
        }

        static void HardwareTestComplete( IAsyncResult iar)
        {
            try {
                AsyncResult ar = (AsyncResult)iar;
                HardwareTestDelegate caller = (HardwareTestDelegate)ar.AsyncDelegate;
                caller.EndInvoke( iar);
            } catch( Exception ex) {
                Console.WriteLine( "Should see this line without getting an unhandled exception message in the IDE");
            }
        }
    }
}

我从线程中抛出我的 HardwareException,然后在调用 EndInvoke 时处理异常。我猜 Murphy 是对的,因为当我运行这个示例代码时,它会按照我的预期运行——即 IDE 中不会弹出未处理的异常错误消息!

4

2 回答 2

2

以下是 Microsoft 的回复,案例 111053102422121。Allen Weng写道:

分析:

供您参考,当您调用 EndInvoke() 时,CLR 将在回调中重新引发异常。下面是 EndInvoke() 的简化版本:

public object EndInvoke(IAsyncResult asyncResult)
{
    using (new MultithreadSafeCallScope())
    {
        ThreadMethodEntry entry = asyncResult as ThreadMethodEntry;
         ............
        if (entry.exception != null)
        {
            throw entry.exception;
        }
     }
}

如果提供了异常处理程序,异常将在回调函数或异步方法中处理。这就是它在没有附加调试器的情况下的工作方式。

当您在 VS.NET 中运行它时,调试器似乎只检查异步方法中是否存在异常处理程序。如果没有这样的处理程序,调试器会认为异常未处理并弹出一条错误消息通知您。

建议:

当您单独运行该应用程序时,它应该可以按预期工作。如果错误消息在调试中对您来说很烦人,您可以通过在异常对话框(调试|异常或按 CTRL+ATL+E)中取消选中“公共语言运行时异常”的“用户未处理”来禁用它。或者您可以在异步方法中添加 try/catch。在后一种情况下,异常设置为 null 并且不会在 EndInvoke() 中重新抛出。

于 2011-05-31T11:11:06.907 回答
0

我遇到了同样的问题,所以为了后代,我会发布这个可能的解决方法:

在您将异常抛出到 .NET 代码中的代码(上例中的 HardwareTestThread())中,捕获抛出的异常并将其包装在一些深奥的 .NET 异常类型中,您可以禁用“用户未处理”选项在“调试”>“例外”对话框中。对于我的情况,我需要允许 IOException 通过一些 .NET 代码传播回我的代码,所以我只是捕获了 IOException 并包装在 AppDomainUnloadedException 中,然后让它通过 .NET 代码传播回我的 catch 块。我选择了 AppDomainUnloadedException,因为默认情况下未选中 user-unhandled 并且它在 System.dll 程序集中,所以它已经被导入到我的项目中,尽管任何异常都应该起作用,只要你禁用“user-unhandled”选项为它而你不

这是包装我需要传播的 IOException 的代码:

public override int Read(byte[] buffer, int offset, int count)
{
    try { return innerStream.Read(buffer, offset, count); }
    catch (IOException ex) { throw new AppDomainUnloadedException("Exception from innerStream: " + ex.Message, ex); }
}

这是我的代码,我在它需要传播的 .NET 代码的另一端捕获它:

try { bytesRead = sslStream.Read(buffer, offset, count); }
catch (Exception ex) { /* ex handled here. */ }
于 2013-01-16T23:04:32.790 回答