Исключение переполнения стека без бесконечного цикла (насколько я могу судить)
У меня ошибка переполнения стека, и я вполне уверен, что у меня нет какой-либо бесконечной рекурсии (по крайней мере, я смотрел на ошибку в течение нескольких часов, и я не могу представить, как она зацикливается бесконечно).
Вот код:
public decimal? Amount
{
get
{
if (!string.IsNullOrEmpty(_savedWork.Amount))
return decimal.Parse(_savedWork.Amount);
else
return null;
}
set
{
if (value.HasValue)
{
_savedWork.Amount = value.Value.ToString();
Percent = null;
}
else
_savedWork.Amount = "";
OnPropertyChanged("Amount");
}
}
# Заметьте, у меня есть строка, содержащая десятичное число, которое можно обнулять, поэтому я ее конвертирую. Пожалуйста, не заставляй меня понимать, почему я это делаю.
линия savedWork.Amount = value.Value.ToString()
где я получаю ошибку.
В основном я думаю, что мой стек слишком мал (или мой код слишком большой). Я в основном запускаю этот код дважды, и он работает, когда в одной форме, но не тогда, когда я создаю другую форму и помещаю ее туда, поэтому я думаю, что разница между этими двумя формами заключается в опрокидывании стека.
Есть ли способ определить, что я делаю не так? Я хочу узнать, какая часть кода занимает слишком много или сохраняется слишком долго и т. Д.
Я провел некоторое исследование о том, как работает стек / куча, и я знаю о PerfMon.exe, но, насколько я знаю, он работает только для кучи. Есть ли подобный инструмент, который я могу использовать для стеков, в которых работает моя программа?
Я нашел этот пост о двух инструментах, называемых windbg и cdb, но я не могу найти много о том, как их установить / использовать. Эти инструменты - правильный путь?
В качестве альтернативы, если есть бесконечный цикл или что-то, что было бы здорово.
редактировать
вот код, запрошенный для свойства Amount (его автоматически генерирует EntityFramework), как я уже говорил в комментариях, шаг в него даже не достигается. Я действительно думаю, что мой предел стека только что достигнут.
public global::System.String Amount
{
get
{
return _Amount;
}
set
{
OnAmountChanging(value);
ReportPropertyChanging("Amount");
_Amount = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("Amount");
OnAmountChanged();
}
}
Окончательное редактирование
Итак, ответ Meta-Knight показал мне, что у меня действительно был бесконечный цикл. У меня был обработчик события, подписанный на событие PropertyChanged DisplayTypeOfInvestment (класса, к которому принадлежит свойство Amount). Обработчик выглядел так:
void DisplayTypeOfInvestmentList_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
_typeOfInvestmentFormSavedWork.TypeOfInvestment.Clear();
foreach (DisplayInvestmentFund d in _displayInvestmentFundList)
{
_typeOfInvestmentFormSavedWork.TypeOfInvestment.Add(d.SavedWork);
}
OnPropertyChanged("TypeOfInvestmentFormSavedWork");
}
TypeOfInvestmentFormSavedWork
это совершенно другой класс, который содержит в себе свою собственную версию класса SavedWork, который, как мы видим, использует свойство Amount. Смысл этого метода состоял в том, чтобы обновить это свойство TypeOfInvestmentFormSavedWork до нового значения _savedWork при изменении свойства Amount. По какой-то причине это вызывает PropertyChanged представления модели представления DisplayTypeOfInvestment. Я не понял это, но я изменил метод, чтобы выглядеть так:
void DisplayTypeOfInvestmentList_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "Amount" || e.PropertyName == "Percent")
{
_savedWork.TypeOfInvestment.Clear();
foreach (DisplayInvestmentFund d in _displayInvestmentFundList)
{
_savedWork.TypeOfInvestment.Add(d.SavedWork);
}
OnPropertyChanged("CurrentWork");
}
}
Оператор if останавливает изменение странных свойств в DisplayInvestmentFund при вызове метода Add.
Я понимаю, что этот ответ не имеет особого смысла, но для того, чтобы объяснить это в деталях, потребуется очень много времени. Я также понимаю, что это, вероятно, означает, что мой код плохой. Я не уверен, что с этим делать. Спасибо за помощь, ребята!
4 ответа
Должен быть рекурсивный вызов Amount
сеттер как-то. Вы можете отлаживать его, "заходя" в свойства, а не переступая. Если вы установите VS так, чтобы он не входил в свойства, вы все равно можете поместить точку останова в свои сеттеры, чтобы имитировать "шаг в". Что касается VS, не входящего в файлы.edmx, как упоминалось в CodeInChaos, возможно, класс помечен атрибутом DebuggerStepThrough.
Я предполагаю, что вы назначаете Amount
в одном из обработчиков событий, OnPropertyChanged
звонки.
Другая возможность состоит в том, что у вас есть код в установщике SavedWork.Amount
что вызывает YourClass.Amount
снова.
Но почему бы тебе просто не отладить это? Просто пошагово пройдитесь по коду в отладчике Visual Studio.
Трассировка стека также должна быть полезной. С бесконечной рекурсией вы обычно получаете повторяющуюся последовательность методов. Если мое предположение верно, повторяющаяся часть будет выглядеть примерно так:
MyClass.set_Amount
MyClass.OnPropertyChanged
OtherClass.myClass_amount_changed
Является ли класс члена Amount того же типа, что и _savedWork?
Потому что может быть этот цикл:
1) Вы присваиваете значение Amount
2) До того, как значение будет установлено, вы назначаете значение _savedWork.Amount
3) До того, как установлено значение _savedWork.Amount, строка запускается снова
4) До того, как будет установлено значение _savedWork._savedWork.Amount...
5) До того, как будет установлено значение _savedWork._savedWork._savedWork.Amount...
И это уходит в бесконечность и дальше.
Является _savedWork
объект того же типа, что и Amount
недвижимость в списке? Потому что это даст вам ошибку переполнения стека! В этом случае вам нужно найти способ поговорить о Amount
без вызова get
тер и set
тер.