Определить, если инициализация класса вызывает бесконечную рекурсию? - PullRequest
0 голосов
/ 15 апреля 2010

Я работаю над переносом приложения VB6 на C # (Winforms 3.5), и в то же время я пытаюсь разбить функциональность на различные классы (например, класс базы данных, класс проверки данных, класс манипуляции строками).

Прямо сейчас, когда я пытаюсь запустить программу в режиме отладки, программа приостанавливается, а затем вылетает с StackOverFlowException . VS 2008 предлагает бесконечную рекурсию причину.

Я пытался отследить, что может быть причиной этой рекурсии, и сейчас моя единственная гипотеза - инициализация классов (что я делаю в заголовке (?) Каждого класса).

Моя мысль такова:

  • mainForm инициализирует classA
  • classA инициализирует classB
  • classB инициализирует classA
  • ....

Имеет ли это смысл или я должен искать в другом месте?

UPDATE1 (пример кода):

MainForm

namespace john
{
    public partial class frmLogin : Form
    {
    stringCustom sc = new sc();

stringCustom

namespace john
{
   class stringCustom
   {
       retrieveValues rv = new retrieveValues();

retrieveValues ​​

namespace john
{
    class retrieveValues
    {
    stringCustom sc = new stringCustom();

Ответы [ 6 ]

5 голосов
/ 15 апреля 2010

9 раз из 10, бесконечные ошибки рекурсии вызваны неправильными средствами доступа к свойствам:

public class BrokenClass
{
    private string name;

    public string Name
    {
        get { return name; }
        set { Name = value; }  // <--- Whoops
    }
}

У меня также было такое, когда я делал серьезные рефакторинги с перегрузками методов; иногда вы случайно получаете метод, вызывающий себя, когда он должен вызвать другой перегруженный метод.

В любом случае, вы должны быть в состоянии определить, просматривая стек вызовов для исключения и проверяя повторяющийся шаблон. Если вы видите один, то ваша проблема где-то в этом цикле.

Редактировать - ну, исходя из вашего примера кода, вы определенно имеете бесконечную рекурсию в инициализаторах. Я понятия не имею, что должен делать этот код, но он никогда не закончится. StringCustom немедленно создает RetrieveValues, что немедленно создает еще один StringCustom и т. Д.

Это одна из причин, по которой циклические зависимости классов обычно считаются запахом кода. Всякий раз, когда вы видите ClassA в зависимости от ClassB и ClassB в зависимости от ClassA, вам следует попытаться выполнить рефакторинг; Исключение составляют случаи, когда ClassB полностью принадлежит и управляется ClassA (то есть внутренним классом), что здесь явно не так. Вам нужно как-то устранить одну из зависимостей.

3 голосов
/ 15 апреля 2010

Просто установите точку останова в конструкторе каждого класса, который вы инициализируете. Если вы продолжаете обращаться к одним и тем же точкам прерывания снова и снова, я бы сказал, что причиной является бесконечная рекурсия.

Я бы также проверил стек, чтобы увидеть, что происходит.

2 голосов
/ 15 апреля 2010

Да, у вас бесконечная рекурсия, потому что у вас есть два класса, которые создают экземпляр другого класса в своих конструкторах. Как только вы создаете экземпляр одного класса, он создает экземпляр другого класса, который создает экземпляр другого класса, который создает экземпляр другого класса и т. Д. И т. Д. И т. Д. И т. Д.

Тебе определенно нужно провести рефакторинг.

1 голос
/ 15 апреля 2010

Ну, все это понимают. Почему бы не предложить какое-то решение?

Теперь я помню эту ситуацию. Один из способов - избежать вызова другого конструктора внутри него. Итак, было бы дополнительное кодирование. Например -

class A {
    B b;
    A() {}
    void Init() { b = new B(); }
}
class B {
    A a;
    B() {}
    void Init() { a = new A(); }
}
...
A aObj = new A();
aObj.Init();
...
B bObj = new B();
bObj.Init();

Это удалит рекурсию. Это, очевидно, самый простой способ. :)

1 голос
/ 15 апреля 2010

Звучит так, что это проблема. Разве вы не можете передать ClassA в конструктор для ClassB?

1 голос
/ 15 апреля 2010

Да, я думаю, вы, вероятно, на правильном пути. Иногда это легко увидеть в отладчике, посмотрев на стек вызовов в точке останова, помещенной в строку кода, которая вызывает исключение.

...