C# 没有递归或无限循环的 StackOverflowException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/778963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
StackOverflowException without recursion or infinite loop?
提问by gnirts
Background
背景
I have a DataGridView
control which I am using, and I added my handler below to the DataGridView.CellFormatting
event so the values in some cells can be made more human-readable. This event handler has been working great, formatting all values without issue.
我有一个DataGridView
我正在使用的控件,我在下面添加了我的处理程序到DataGridView.CellFormatting
事件中,以便可以使某些单元格中的值更易于人类阅读。此事件处理程序运行良好,可以毫无问题地格式化所有值。
Recently however, I have discovered a very rare circumstance causes an unusual bug. The column in my DataGridView
for the item's due date always has an int
value. 0
indicates the event is never due, any other value is a UTC timestamp for the due date. The MySQL db column corresponding doesn't allow nulls. When the user has moved from one DataGridView
row with a due date, to another DataGridView
row with a due date (at this point everything is still appears fine), and then presses a button which reloads the data from the database (without sending updates, essentially calling DataAdapter.Fill()
), the program generates a StackOverflowException
**.
然而,最近我发现一种非常罕见的情况会导致一个不寻常的错误。myDataGridView
中项目到期日的列始终具有int
值。0
表示事件永远不会到期,任何其他值都是到期日期的 UTC 时间戳。对应的 MySQL db 列不允许空值。当用户从DataGridView
具有截止日期的一行移动到具有截止日期的另一DataGridView
行时(此时一切仍然显示正常),然后按下一个按钮从数据库重新加载数据(不发送更新,本质上调用DataAdapter.Fill()
),程序生成一个StackOverflowException
**。
No recursion?
没有递归?
What is so unusual to me is that I do not see where the recursion or infinte-looping is. I added int cellFormatCallCount
as a class member, and increment it during each call, but at the time the exception is thrown, the debugger shows the value of that int
as 1, which I would expect since I wasn't under the impression and recursion was occuring.
对我来说如此不寻常的是,我看不到递归或无限循环在哪里。我添加int cellFormatCallCount
为一个类成员,并在每次调用期间增加它,但是在抛出异常时,调试器将它的值显示int
为 1,这是我所期望的,因为我没有印象并且正在发生递归。
Can somebody help me?
有人可以帮助我吗?
How can I view a stack trace? In VS2008 it says:
{Cannot evaluate expression because the current thread is in a stack overflow state.}
如何查看堆栈跟踪?在 VS2008 中它说:
{Cannot evaluate expression because the current thread is in a stack overflow state.}
Best regards,
此致,
Robinson
罗宾逊
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
}
}
采纳答案by Henk Holterman
Apparently e.Value.ToString() invokes the CellFormatting event again. That seems somewhat logical. It should be easy enough to find out with a debugger.
显然 e.Value.ToString() 再次调用 CellFormatting 事件。这似乎有些合乎逻辑。使用调试器应该很容易找到。
But the actual recursion could be caused somewhere else, like in the per-column formatting that you omitted.
但是实际的递归可能是在其他地方引起的,例如您省略的每列格式。
Your recursion check isn't reliable since Value==null will also reset it, and it appears to be shared by all columns. Make it surround the e.Value.ToString() more tightly:
您的递归检查不可靠,因为 Value==null 也会重置它,并且它似乎由所有列共享。让它更紧密地包围 e.Value.ToString():
if (e.Value != null)
{
cellFormatCallCount++;
System.Diagnostics.Debug.Assert(cellFormatCallCount <= 1, "Recursion");
value = e.Value.ToString();
cellFormatCallCount--;
...
}
回答by Daniel LeCheminant
Totally random guess (with no stack trace it's all I can do)...
完全随机猜测(没有堆栈跟踪这是我所能做的)......
Are you attempting to display/format a type which has a potentially recursive ToString()
?
您是否试图显示/格式化具有潜在递归的类型ToString()
?
public string ToString()
{
return ... this.ToString() ...
// or
return String.Format("The value is {0}", this);
}
A typo/error like that could cause a StackOverflowException
...
像这样的错字/错误可能会导致StackOverflowException
...
回答by Mehrdad Afshari
It's unrelated to the problem but you can actually have a StackOverflowException
without recursion at all just with:
它与问题无关,但实际上您可以完全StackOverflowException
不使用递归:
throw new StackOverflowException();
回答by asgerhallas
@Daniel: If that were the issue, wouldn't it already raise the exception in the line:
@Daniel:如果这是问题,它是否已经在该行中引发异常:
if (e.Value != null) {
@gnirts: Could you post the full method and stack trace too?
@gnirts:您能否也发布完整的方法和堆栈跟踪?
@BCS (below): I think that might be it, but it might easily be in some of the code that is not shown in the deo posted.
@BCS(下):我认为可能就是这样,但它可能很容易出现在一些未在发布的 deo 中显示的代码中。
PS. I'm sorry, this should have been a comment, but I have not enough reps :-D
附注。对不起,这应该是评论,但我没有足够的代表:-D
回答by BCS
Given that this is an event, might it be triggering its self?
鉴于这是一个事件,它是否会触发自身?
回答by tvanfosson
Try making the cellFormatCallCount variable static so that it shared by all instances of the class. I suspect that somehow the event is triggering itself but you aren't seeing it because cellFormatCallCount is only local to each instance of the class handling the event and thus is never incremented beyond 1. If that's the case, then the actual trigger for the stackoverflow (recursion) could be anywhere in the method and it just happens to run out of stack space at that line.
尝试将 cellFormatCallCount 变量设为静态,以便该类的所有实例共享它。我怀疑该事件以某种方式触发了自己,但您没有看到它,因为 cellFormatCallCount 只是处理该事件的类的每个实例的本地,因此永远不会增加超过 1。如果是这种情况,则是 stackoverflow 的实际触发器(递归)可以在方法中的任何地方,并且恰好在该行用完堆栈空间。
Once you've made the variable static, you could throw an exception when it exceeds a certain (small) value, like 2. That exception should leave a viewable stack trace around.
一旦您将变量设为静态,当它超过某个(小)值时,您就可以抛出异常,例如 2。该异常应该留下一个可见的堆栈跟踪。
回答by peterincumbria
I Have just had a similar problem of stackoverflow with no trace details.
我刚刚遇到了类似的 stackoverflow 问题,但没有跟踪详细信息。
My problem was due to a instance of an object which should not have been instantiated. I removed the offending new object and all was fine.
我的问题是由于一个不应该被实例化的对象实例。我删除了有问题的新对象,一切都很好。
In the circumstance above without seeing any more code, ensure multiple events are not fired using the =- to cancel the events accordingly.
在上面没有看到更多代码的情况下,确保不会触发多个事件,使用 =- 相应地取消事件。
I hope this might help someone.
我希望这可以帮助某人。