8

背景

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

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

没有递归?

对我来说如此不寻常的是,我看不到递归或无限循环在哪里。我添加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
    }
}
4

7 回答 7

5

显然 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--; 
   ...
} 
于 2009-04-23T03:43:01.543 回答
2

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

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

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

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

于 2009-04-22T20:11:48.027 回答
1

@Daniel:如果这是问题所在,它是否已经在该行中引发了异常:

if (e.Value != null) {

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

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

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

于 2009-04-22T20:16:55.033 回答
1

鉴于这是一个事件,它可能会触发它自己吗?

于 2009-04-22T20:18:22.923 回答
1

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

将变量设为静态后,当它超过某个(小)值(如 2)时,您可能会引发异常。该异常应留下可见的堆栈跟踪。

于 2009-04-22T20:24:43.377 回答
0

它与问题无关,但实际上你可以完全StackOverflowException没有递归:

throw new StackOverflowException();
于 2009-04-22T20:14:17.770 回答
0

我刚刚遇到了类似的 stackoverflow 问题,没有跟踪详细信息。

我的问题是由于不应该实例化的对象实例造成的。我删除了有问题的新对象,一切都很好。

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

我希望这可以帮助某人。

于 2012-01-11T13:24:38.497 回答