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.
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
**.
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.
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.}
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
}
}
NET Framework 2.0, you can't catch a StackOverflowException object with a try / catch block, and the corresponding process is terminated by default. Consequently, you should write your code to detect and prevent a stack overflow.
A StackOverflowException is thrown when the execution stack overflows because it contains too many nested method calls. using System; namespace temp { class Program { static void Main(string[] args) { Main(args); // Oops, this recursion won't stop. } } }
The most-common cause of stack overflow is excessively deep or infinite recursion, in which a function calls itself so many times that the space needed to store the variables and information associated with each call is more than can fit on the stack.
If a recursion never reaches a base case, it will go on making recursive calls forever and the program will never terminate. This is known as infinite recursion, and it is generally not considered a good idea. In most programming environments, a program with an infinite recursion will not really run forever.
Apparently e.Value.ToString() invokes the CellFormatting event again. That seems somewhat logical. It should be easy enough to find out with a debugger.
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:
if (e.Value != null)
{
cellFormatCallCount++;
System.Diagnostics.Debug.Assert(cellFormatCallCount <= 1, "Recursion");
value = e.Value.ToString();
cellFormatCallCount--;
...
}
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()
?
public string ToString()
{
return ... this.ToString() ...
// or
return String.Format("The value is {0}", this);
}
A typo/error like that could cause a StackOverflowException
...
Given that this is an event, might it be triggering its self?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With