StackOverflowException без рекурсии или бесконечного цикла?
фон
у меня есть 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
}
}
7 ответов
видимо е.Значение.ToString () снова вызывает событие CellFormatting. Это кажется несколько логичным. Это должно быть достаточно легко выяснить с помощью отладчика.
но фактическая рекурсия может быть вызвана где-то еще, например, в форматировании каждого столбца, которое вы опустили.
ваша проверка рекурсии ненадежна, так как Value==null также сбросит ее, и она, похоже, разделяется всеми столбцами. Сделать его окружают е.Значение.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
...
попробуйте сделать переменную cellFormatCallCount статической, чтобы она была общей для всех экземпляров класса. Я подозреваю, что каким-то образом событие запускает себя, но вы его не видите, потому что cellFormatCallCount является локальным только для каждого экземпляра класса, обрабатывающего событие, и поэтому никогда не увеличивается за 1. Если это так, то фактический триггер для stackoverflow (рекурсии) может быть в любом месте метода, и при этом просто заканчивается пространство стека линия.
Как только вы сделали переменную статической, вы можете создать исключение, когда оно превышает определенное (небольшое) значение, например 2. Это исключение должно оставлять видимую трассировку стека.
@Daniel: если бы это было проблемой, разве это уже не вызвало бы исключение в строке:
if (e.Value != null) {
@gnirts:не могли бы вы опубликовать полный метод и трассировку стека?
@BCS (ниже): я думаю, что это может быть так, но это может быть легко в некотором коде, который не показан в опубликованном deo.
PS. Извините, это должен был быть комментарий, но у меня недостаточно повторений : - D
это не связано с проблемой, но вы действительно можете иметь StackOverflowException
без рекурсии вообще просто с:
throw new StackOverflowException();
У меня только что была аналогичная проблема stackoverflow без деталей трассировки.
моя проблема была связана с экземпляром объекта,который не должен был быть создан. Я удалил оскорбительный новый объект, и все было в порядке.
в обстоятельствах выше, не видя больше кода, убедитесь, что несколько событий не запускаются с помощью = - для отмены событий соответственно.
Я надеюсь, что это может помочь кому-то.