Почему я получаю 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 шт):
Причина ошибки - бесконечная рекурсия. Формы создают друг друга вызывая конструкторы бесконечно, пока не заканчивается стек. Инициализаторы полей, как вы изначально сделали, выполняются вместе с конструктором класса, то есть равносильно тому, что вы эти new указали бы в самом конструкторе.
Форма, это такой объект, который не стоит переиспользовать, если вы с нее ушли. Закончили пользоваться - закрыли Close(), снова понадобилась - создали заново new, затем показали Show().
На это поведение завязано очень много механик самих винформ. Теоретически сделать форму синглтоном можно, но только это если реально требуется. Например юзер работал с формой и внезапно вы решили его прервать, а потом снова вернуть к рабочей форме ровно в том состоянии в котором она была. Но это редкий, практически исключительный случай. Поэтому не стесняйтесь, создать форму - не тяжелая задача, вам же не нужно тысячи форм в секунду создавать.
Осторожнее с Hide(), спрятанная форма продолжает висеть в памяти в рабочем состоянии. Если вы этот же экземпляр формы не вернете на экран или не закроете через Close(), приложение так и останется висеть в памяти, если пользователь закроет все окна, потому что по факту часть окон не будет закрыта, а будет просто спрятана.