Почему я получаю System.StackOverflowException?

Изучаю работу с WinForms. Тот самый случай, когда я знаю как исправить ошибку, но не понимаю почему она возникла. У меня есть 2 формы RegisterForm и LoginForm. Когда я в классах каждой из них создаю экземпляр противоположной, я получаю System.StackOverflowException

Вот код(укороченный, минимальный пример, в котором суть)

LoginForm

public partial class LoginForm : Form
    {

        RegisterForm registerform = new RegisterForm();

        public LoginForm()
        {
            InitializeComponent();
        }

        private void to_register_Click(object sender, EventArgs e)
        {
            try
            {
                this.Hide();
                registerform.Show();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }

RegisterForm

    public partial class RegisterForm : Form
    {
        LoginForm loginForm = new LoginForm();

        public RegisterForm()
        {
            InitializeComponent();
        }

       private void to_login_Click(object sender, EventArgs e)
        {
            try
            {
                this.Hide();
                loginForm.Show();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }
    }

Я это починил путем создания экземплера при клике кнопки.

// В начале самого класса объявлено RegisterForm registerform; (Не в конструкторе)
private void to_register_Click(object sender, EventArgs e)
        { 
            try
            {
                this.Hide();
                registerform = new RegisterForm();
                registerform.Show();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

Не знаю насколько это правильно. Мне бы хотелось просто узнать почему я получал System.StackOverflowException. И правильный путь решения ошибки, если мой неверный. Возможно стоит создавать эти переменные в конструкторе или загрузчике формы?


Ответы (1 шт):

Автор решения: aepot

Причина ошибки - бесконечная рекурсия. Формы создают друг друга вызывая конструкторы бесконечно, пока не заканчивается стек. Инициализаторы полей, как вы изначально сделали, выполняются вместе с конструктором класса, то есть равносильно тому, что вы эти new указали бы в самом конструкторе.

Форма, это такой объект, который не стоит переиспользовать, если вы с нее ушли. Закончили пользоваться - закрыли Close(), снова понадобилась - создали заново new, затем показали Show().

На это поведение завязано очень много механик самих винформ. Теоретически сделать форму синглтоном можно, но только это если реально требуется. Например юзер работал с формой и внезапно вы решили его прервать, а потом снова вернуть к рабочей форме ровно в том состоянии в котором она была. Но это редкий, практически исключительный случай. Поэтому не стесняйтесь, создать форму - не тяжелая задача, вам же не нужно тысячи форм в секунду создавать.

Осторожнее с Hide(), спрятанная форма продолжает висеть в памяти в рабочем состоянии. Если вы этот же экземпляр формы не вернете на экран или не закроете через Close(), приложение так и останется висеть в памяти, если пользователь закроет все окна, потому что по факту часть окон не будет закрыта, а будет просто спрятана.

→ Ссылка