views:

84

answers:

4

I have a small code sample:

private void MonitorItems()
        {
            if (someCondition)
            {
                dateSelected = DateTime.Now;
                GetAllItems();
            }
            else
            {
                if(allItems.Count>0)
                    CheckAllItems();
            }
            MonitorItems();
        }

The Method GetAllItems goes to DB and get all new items for the collection -> allItems. Then, the CheckAllItems method:

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;
                }
            }  
        }

In some cases (in HandleStatus1 and HandleStatus2) i need to go to the DB, make some updates, and then again populate the collection allItems with calling the method GetAllItems.

This type of code is throwing Stack.Overflow exception in WinFormsApp. I have two questions:
1. Is this type of exception will be thrown in WinService application, using the same code?
2. What is your opinion of using timers instead of self-calling method?

+1  A: 

A "self-calling method" is more correctly called a "recursive method". Your solution is creative, I'll give you that. But don't do it. Stack space is very limited. You will see this problem when you move to a service, and there are much better ways of handling this. A timer is very appropriate when used in a service.

Michael Petrotta
First implementation was planned to be with timer. But i had one problem. The timer is set to Tick on 1 sec. What will happen if the work in CheckAllItems() is not finished and the timer ticks again? Little explanation about the code: there must be a recursive call so the monitoring wont stop.
ZokiManas
@ZM: If you use the System.Timers.Timer class, and the timer ticks again before your processing of the previous event completes, your handler will be called again, on a different thread. Make sure your code can handle that (in other words, make sure that your code is reentrant). If you don't want this behavior, you can Stop() the timer in your handler, then Start() it again when you're done.
Michael Petrotta
@ZM: in case it wasn't clear before, your recursive calls are not just a bad idea, they're a **really** bad idea. Don't do it.
Michael Petrotta
Also, note that it's not safe to touch UI objects (buttons, text boxes, etc) from the handlers for these timers. If you need to do this, look into System.Forms.Timer, or BeginInvoke(). If you don't touch UI objects, you're generally ok.
Michael Petrotta
I've marked this answer as a correct one just because i've used System.Timers.Timer and realized that the method is called again and again on a different threads. So far, everything is working as expected. Thanks Michael.
ZokiManas
+1  A: 

Recursive calling the method in your case is as bad as using a timer to do it. You should do neither!!

Just use a simple loop and send the thread sleeping for some time in between.

Foxfire
@Foxfire: what's wrong with a timer?
Michael Petrotta
+1 timers are not good choice
Trickster
Nothing if correctly used. But if he creates code like that I fear that he will create the timer in the wrong place which might also lead to recursions (in fact much harder to find ones).
Foxfire
I think timers are used when we have something to do while timer waits to fire event. In his case program has nothing to do. So let it sleep
Trickster
@Trickster: Foxfire's point is well taken; proper use of timers needs care. Given that, timers have well-defined uses; say you wish to execute a task every ten seconds precisely. You might also be unaware of the System.Threading.Timer class, as distinct from the System.Windows.Forms.Timer component.
Michael Petrotta
A: 

MS IL has .tail op code. But c# dot want to recognize tail recursion (. By the way, tail recursion is so slow in .net ((

Trickster
A: 

Why do you need to recurse at all? There is no flow control statement that will allow the method to stop recursing and exit the chain. The infinite recursions is probably what is causing the overflow. A better solution would to do away with the recursion altogether. Removing the else wrapper accomplishes the same result without having to recurse:

private void MonitorItems()
{
    if(someCondition)
    {
        dateSelected = DateTime.Now;
        GetAllItems();
    }
    if(allItems.Count>0)
        CheckAllItems();
}

This will accomplish the same result without getting stuck in a loop. Then you can implement rules to repeat the call in the context of the execution environment: a button click on a form or a timer on a service application.

Jeremy Seghi