Ошибка Stack.Overflow - приложение WinForms WinService
-
06-07-2019 - |
Вопрос
У меня есть небольшой пример кода:
private void MonitorItems()
{
if (someCondition)
{
dateSelected = DateTime.Now;
GetAllItems();
}
else
{
if(allItems.Count>0)
CheckAllItems();
}
MonitorItems();
}
Метод GetAllItems отправляется в БД и получает все новые элементы для коллекции - > все элементы. Затем метод CheckAllItems:
private void CheckAllItems()
{
foreach (Item a in new List<Item>(allItems))
{
switch (a.Status)
{
case 1:
HandleStatus1();
break;
case 2:
HandleStatus2(a);
break;
case 0:
HandleStatus0(a);
break;
default:
break;
}
}
}
В некоторых случаях (в HandleStatus1 и HandleStatus2) мне нужно перейти в БД, внести некоторые обновления, а затем снова заполнить коллекцию allItems, вызвав метод GetAllItems.
Этот тип кода вызывает исключение Stack.Overflow в WinFormsApp.
У меня два вопроса:
1. Будет ли исключение такого типа генерироваться в приложении WinService с использованием того же кода?
2. Каково ваше мнение об использовании таймеров вместо метода самостоятельного вызова?
Решение
"Самовозвратный метод" более правильно называется " рекурсивный метод " . Ваше решение креативно, я дам вам это. Но не делай этого. Пространство стека очень ограничено. Вы увидите эту проблему при переходе на службу, и есть гораздо лучшие способы решения этой проблемы. Таймер очень подходит для использования в сервисе.
Другие советы
Рекурсивный вызов метода в вашем случае такой же плохой , как и использование таймера для этого. Вы не должны делать ни один из них!
Просто используйте простой цикл и отправьте поток в спящий режим на некоторое время.
MS IL имеет код операции .tail. Но c # dot хочет распознать хвостовую рекурсию (кстати, хвостовая рекурсия в .net такая медленная ((
Зачем вам вообще нужно проходить курс? Нет оператора управления потоком, который позволил бы методу прекратить рекурсию и выйти из цепочки. Бесконечные рекурсии, вероятно, являются причиной переполнения. Лучшее решение - полностью отказаться от рекурсии. Удаление оболочки обертки приводит к тому же результату без необходимости повторять:
private void MonitorItems()
{
if(someCondition)
{
dateSelected = DateTime.Now;
GetAllItems();
}
if(allItems.Count>0)
CheckAllItems();
}
Это даст тот же результат без зацикливания. Затем вы можете реализовать правила для повторения вызова в контексте среды выполнения: нажатие кнопки на форме или таймер в приложении-службе.