繁体   English   中英

StackOverflowException没有递归或无限循环?

[英]StackOverflowException without recursion or infinite loop?

背景

我有一个我正在使用的DataGridView控件,我在下面将我的处理程序添加到DataGridView.CellFormatting事件中,因此可以使某些单元格中的值更易于阅读。 这个事件处理程序一直很好,格式化所有值没有问题。

然而,最近我发现了一个非常罕见的情况导致一个不寻常的错误。 我的DataGridView用于项目到期日期的列始终具有int值。 0表示事件永远不会到期,任何其他值都是截止日期的UTC时间戳。 相应的MySQL db列不允许空值。 当用户从具有截止日期的一个DataGridView行移动到具有截止日期的另一个DataGridView行时(此时一切仍然显示正常),然后按下一个从数据库重新加载数据的按钮(不发送更新,本质上调用DataAdapter.Fill() ),程序生成一个StackOverflowException **。

没有递归?

对我来说不寻常的是,我没有看到递归或infinte-looping的位置。 我添加了int cellFormatCallCount作为类成员,并在每次调用期间递增它,但是在抛出异常时,调试器将该int的值显示为1,这是我所期望的,因为我不在印象和递归之下发生了。

有人能帮助我吗?

如何查看堆栈跟踪? 在VS2008中,它说: {Cannot evaluate expression because the current thread is in a stack overflow state.}

最好的祝福,

罗宾逊

private int cellFormatCallCount = 0;
private void myDataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)  {
    try {
        // to format the cell, we will need to know its value and which column its in
        string value = "";
        string column = "";

        // the event is sometimes called where the value property is null
        if (e.Value != null) {
            cellFormatCallCount++; // here is my test for recursion, this class member will increment each call

            // This is the line that throws the StackOverflowException
            /* ********************* */
            value = e.Value.ToString();
            /* ********************* */

            column = actionsDataGridView.Columns[e.ColumnIndex].Name;
        } else {
            return; // null values cannont be formatted, so return
        }

        if (column == "id") {
            // different code for formatting each column
        } else if (column == "title") {
            // ...
        } else {
            // ...
        }
    } finally {
        cellFormatCallCount = 0; // after we are done with the formatting, reset our recursion counter
    }
}

显然e.Value.ToString()再次调用CellFormatting事件。 这似乎有点合乎逻辑。 使用调试器找出它应该很容易。

但实际的递归可能会在其他地方引起,就像你省略的每列格式一样。

您的递归检查不可靠,因为Value == null也会重置它,并且它似乎由所有列共享。 使它更紧密地环绕e.Value.ToString():

if (e.Value != null) 
{
   cellFormatCallCount++; 
   System.Diagnostics.Debug.Assert(cellFormatCallCount <= 1, "Recursion");
   value = e.Value.ToString();
   cellFormatCallCount--; 
   ...
} 

完全随机猜测(没有堆栈跟踪,这是我所能做的)......

您是否尝试显示/格式化具有潜在递归ToString()

public string ToString()
{
   return ... this.ToString() ...
   // or
   return String.Format("The value is {0}", this);
}

像这样的错字/错误可能导致StackOverflowException ...

@Daniel:如果那是问题,它不会在行中引发异常:

if (e.Value != null) {

@gnirts:你也可以发布完整的方法和堆栈跟踪吗?

@BCS(下面):我认为可能是它,但它可能很容易出现在deo发布的一些代码中。

PS。 对不起,这应该是评论,但我没有足够的代表:-D

鉴于这是一个事件,它可能会引发它的自我吗?

尝试将cellFormatCallCount变量设置为静态,以便它由类的所有实例共享。 我怀疑事件是以某种方式触发它自己但你没有看到它,因为cellFormatCallCount只对处理事件的类的每个实例都是本地的,因此永远不会超过1.如果是这种情况,那么stackoverflow的实际触发器(递归)可以在方法中的任何地方,它恰好在该行的堆栈空间用完。

一旦你将变量设置为static,你可以在它超过某个(小)值时抛出异常,例如2.该异常应该留下可查看的堆栈跟踪。

它与问题无关,但实际上你可以实现一个StackOverflowException而不需要递归,只需:

throw new StackOverflowException();

我刚刚遇到类似stackoverflow的问题而没有跟踪细节。

我的问题是由于一个不应该被实例化的对象的实例。 我删除了违规的新对象,一切都很好。

在上面没有看到任何代码的情况下,确保不使用= - 触发多个事件来相应地取消事件。

我希望这可以帮助某人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM