C#WPF Window.ShowDialog堆栈溢出异常

C#WPF Window.ShowDialog堆栈溢出异常,c#,wpf,stack-overflow,showdialog,C#,Wpf,Stack Overflow,Showdialog,令人惊讶的是,反复异步调用Window.ShowDialog可能会导致堆栈溢出异常 public MainWindow() { InitializeComponent(); TheCallDelegate = TheCall; _timer = new DispatcherTimer(); _timer.Tick += _timer_Tick; _timer.Start(); } DispatcherTimer _timer = null; void

令人惊讶的是,反复异步调用Window.ShowDialog可能会导致堆栈溢出异常

public MainWindow()
{
    InitializeComponent();
    TheCallDelegate = TheCall;
    _timer = new DispatcherTimer();
    _timer.Tick += _timer_Tick;
    _timer.Start();
}

DispatcherTimer _timer = null;

void _timer_Tick(object sender, EventArgs e)
{
    _timer.Dispatcher.BeginInvoke(TheCallDelegate);            
}

Action TheCallDelegate;

void TheCall()
{
    Window win = new Window();
    win.ShowDialog();
}
正如您所看到的,这里没有实际的递归(或者不应该有),但是一旦发生异常,您可以看到调用堆栈确实已满。 为什么? 这也可以在不使用计时器的情况下实现,例如:

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        while (true)
        {
            this.Dispatcher.BeginInvoke(TheCallDelegate);
            await Task.Delay(1);
        }
    }

另外,你在这里看到的代码是专门用来说明这个问题的,所以不要关注为什么会有人这样做。该问题的目的是了解ShowDialog为何会以这种方式运行。

因为您应该能够看到堆栈跟踪,每次调用
ShowDialog()
都会将新帧推送到堆栈上。由于您多次调用
ShowDialog()
而没有关闭,因此每次调用都会增加堆栈深度,堆栈最终会溢出

这是因为与
Show()
方法不同,
ShowDialog()
在显示的窗口关闭之前不会返回。这与任何其他方法调用一样,因此会导致堆栈增长。由于
ShowDialog()
必须响应用户输入,因此它会启动一个新的调度程序循环。由于调度器仍在运行,所以计时器会不断触发并打开新的嵌套对话框

因此,在非常高的级别上,您的调用堆栈将如下所示:

...Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...

当新对话框打开时,最终会溢出。

因为您应该能够看到堆栈跟踪,所以对
ShowDialog()
的每次调用都会将新帧推送到堆栈上。由于您多次调用
ShowDialog()
而没有关闭,因此每次调用都会增加堆栈深度,堆栈最终会溢出

这是因为与
Show()
方法不同,
ShowDialog()
在显示的窗口关闭之前不会返回。这与任何其他方法调用一样,因此会导致堆栈增长。由于
ShowDialog()
必须响应用户输入,因此它会启动一个新的调度程序循环。由于调度器仍在运行,所以计时器会不断触发并打开新的嵌套对话框

因此,在非常高的级别上,您的调用堆栈将如下所示:

...Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...

随着新对话框的打开,最终会溢出。

查看堆栈应该可以澄清问题。。。如果它没有提供足够的信息给你-张贴堆栈的小重复部分的问题。查看堆栈应该澄清问题。。。如果它没有向您提供足够的信息-将堆栈的一小部分重复发布到问题中。回答“这是因为与Show()方法不同,ShowDialog()在其显示的窗口关闭之前不会返回。这与任何其他方法调用一样,因此会导致堆栈增长。”我不同意。如果我将对ShowDialog的调用替换为阻塞(不让调用返回)的其他调用,堆栈不会堆积(如预期的那样)。所以这两句话至少有误导性。但是新的Dispatcher循环是有意义的,所以感谢您的回答+1响应“这是因为与Show()方法不同,ShowDialog()在显示的窗口关闭之前不会返回。这与任何其他方法调用一样,因此会导致堆栈增长。”我不同意。如果我将对ShowDialog的调用替换为阻塞(不让调用返回)的其他调用,堆栈不会堆积(如预期的那样)。所以这两句话至少有误导性。但是新的Dispatcher循环是有意义的,所以感谢您的回答+1.