Исключение переполнения стека без бесконечного цикла (насколько я могу судить)

У меня ошибка переполнения стека, и я вполне уверен, что у меня нет какой-либо бесконечной рекурсии (по крайней мере, я смотрел на ошибку в течение нескольких часов, и я не могу представить, как она зацикливается бесконечно).

Вот код:

    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тер.

Другие вопросы по тегам