Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异常处理循环难题_C#_.net_Exception_Exception Handling - Fatal编程技术网

C# 异常处理循环难题

C# 异常处理循环难题,c#,.net,exception,exception-handling,C#,.net,Exception,Exception Handling,我最近遇到了一个我从未见过的行为。我不能完全理解发生了什么,很可能是因为缺乏关于内部工作异常处理的基本知识——或者我只是缺少了一些明显的东西 我最近在一个应用程序中添加了异常处理,作为未处理异常的一种回退。我基本上是在处理ThreadException和UnhandleException,如下所示: // Add the event handler for handling UI thread exceptions to the event. Application.ThreadExceptio

我最近遇到了一个我从未见过的行为。我不能完全理解发生了什么,很可能是因为缺乏关于内部工作异常处理的基本知识——或者我只是缺少了一些明显的东西

我最近在一个应用程序中添加了异常处理,作为未处理异常的一种回退。我基本上是在处理ThreadException和UnhandleException,如下所示:

// Add the event handler for handling UI thread exceptions to the event.
Application.ThreadException += new ThreadExceptionEventHandler(ExceptionHandler.OnUIThreadException);

// Set the unhandled exception mode to force all Windows Forms errors to go through
// our handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

// Add the event handler for handling non-UI thread exceptions to the event. 
AppDomain.CurrentDomain.UnhandledException +=
    new UnhandledExceptionEventHandler(ExceptionHandler.OnUnhandledException);

// Runs the application.
Application.Run(new ErrorHandlerForm());
我在应用程序中的另一段代码已经捕获了异常——由于我没有进行异常处理,我只是重新调用异常以确保它不会被吞没:

//code in some method of the Program
try
{
   foo.SomeFooCall();
}
catch(Exception ex)
{
  logger.Log(ex.Message);
  // I don't swallow!
  throw;
}
一旦我有了异常处理(这也是日志记录),我应该删除上面的try-catch块——但是我忘记了这么做,我遇到了一个奇怪的行为,这就是这个问题的主题

当在foo调用中的某个地方抛出and exception时,显然会被上面的代码捕获,记录下来,然后再次抛出。此时ExceptionHandling启动,执行一些日志记录和通知(一个简单的消息框),然后转到
Application.Exit()
。接下来的情况是,应用程序将返回相同的
throw
,这将触发具有相同结果的错误处理,并且这将持续多次,直到崩溃,可能是因为堆栈跟踪已满或检测到无限循环。

编辑:以上是调试模式-如果我只是运行它,它将处理一次异常(显示messagebox、日志等),然后它将崩溃(我猜是堆栈溢出)。

我预计这个问题的答案可能很琐碎(或者我可能遗漏了一些明显的东西),但任何提示/解释都将受到高度赞赏

编辑: 异常处理程序方法将这两个调用都向下调用到OneException方法,如下所示:

private void OnUIThreadException(object sender, ThreadExceptionEventArgs e)
{
   OnException(e.Exception);
}

private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
   OnException((Exception)e.ExceptionObject);
}

private void OnException(Exception exception)
{
   MessageBox.Show("Fatal Exception: " + exception.Message);

   logger.Log(LoggingLevel.FATAL, "myLousyApp", exception.Message);

   Application.Exit();
}
实际上,我做的smt不仅仅是这些——比如询问用户是否想重新启动应用程序,如果是这样,则使用进程id作为cmd arg重新启动应用程序,这样当它重新启动时,它将等待旧进程退出(通过互斥锁保护它不受重复实例的影响)。但对于这个问题,这是无关的,因为当我体验到所描述的行为时,我没有重新启动应用程序


编辑:我创建了另一个简单的应用程序来重现这种情况-我有一个简单的组件可以抛出异常(我在一个循环中抛出任意数量的异常),但在我对应用程序的所有测试中。退出应用程序只会很好地关闭,我无法重现它。对我应该寻找的东西感到困惑

我怀疑在
ExceptionHandler.OnUnhandledException
中可能会引发一个新的异常,该异常保持未处理状态,并冒泡到未处理的异常处理程序,从而引发您的
ExceptionHandler.OnUnhandledException
方法等等。。(无限循环->堆栈溢出)

因此,请仔细检查OnUnhandledException方法是否存在抛出的错误


编辑:有趣的是,我试图重现你的错误,但不是一次又一次地抛出错误,而是我的应用程序。只要在未处理的异常处理程序方法之后退出,不管其中发生了什么。你是在调试还是在运行?这可能会造成不同。

如果不知道原始抛出的代码在做什么,很难判断。可能存在未完成的表单事件,这些事件作为应用程序关闭的一部分进行处理,最终重新调用原始代码片段。它也可以是应用程序类上的一个虚拟函数,在关闭期间被调用


不过,您应该能够从catch处理程序中打印堆栈跟踪来找出它。

tl;dr:是调试器。分离,你就不会有这种奇怪的行为


好的。我对一个全新的项目做了一些实验,得出了一个结果。我将首先发布代码,这样您也可以参与其中,并直接看到它

德科兹 (无关)

表格1.cs
表单上需要两个按钮。适当地给他们加上标题,这样你所做的事情就显而易见了

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        throw new InvalidOperationException("Exception thrown from UI thread");
    }

    private void button2_Click(object sender, EventArgs e)
    {
        new Thread(new ThreadStart(ThrowThreadStart)).Start();
    }

    private static void ThrowThreadStart()
    {
        throw new InvalidOperationException("Exception thrown from background thread");
    }
}
Program.cs 项目文件 禁用宿主进程,否则AppDomain(和表单本身)将不会在调试会话之间卸载,这将使行
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException,false)UnhandledExceptionMode
参数,则code>抛出一个
InvalidOperationException
。编辑:如果设置为CatchException,则完全编辑

对于本次调查来说,这并不是绝对必要的,但如果您打算改变
未处理的异常模式
——我想如果您自己运行此代码,您可能会这样做——此设置会让您省心。

测试 在调试器内部 加入UI线程
  • 在UI中单击抛出
  • 在调试器中获取“未处理的异常”帮助程序
  • F5
    继续执行
  • 对话框将显示,指示应用程序处理程序从UI线程接收到异常事件
  • 单击“确定”
  • 应用程序不会崩溃,所以可以随意冲洗和重复
  • 加入背景线
  • 单击“在背景中加入”
  • 对话框将显示,指示AppDomain处理程序从后台线程接收到异常事件
  • 在调试器中获取“未处理的异常”帮助程序
  • F5
    继续执行
  • 转到2
    。真的
  • 在这里,AppDomain处理程序似乎以任何理由胜过调试器。但是,在AppDomain处理完它之后,调试器会设法发现未处理的异常。但接下来发生的事情令人费解:AppDomain处理程序再次运行。一次又一次。再一次,无限。放br
    static class Program
    {
        [STAThread]
        static void Main()
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            Application.ThreadException += Application_ThreadException;
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, false);
    
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    
        static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            if (e.Exception != null)
            {
                MessageBox.Show(string.Format("+++ Application.ThreadException: {0}", e.Exception.Message));
            }
            else
            {
                MessageBox.Show("Thread exception event fired, but object was not an exception");
            }
        }
    
        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Exception ex = e.ExceptionObject as Exception;
    
            if (ex != null)
            {
                MessageBox.Show(string.Format("*** AppDomain.UnhandledException: {0}", ex.Message));
            }
            else
            {
                MessageBox.Show("Unhandled exception event fired, but object was not an exception");
            }
        }
    }