oldtimeprogrammer
oldtimeprogrammer

Reputation: 3

Process Terminated due to stack overflow

So this is a small piece of c# code mimicking tumbler dials.

Main Program here - Instantiating two Tumblers -- while one of it references the first. The idea is when Tumbler x completes a rotation "resets" and triggers an event that triggers Tumbler y to actuate and increment

class Program
{ 
   public static Tumbler x;
    public static Tumbler y;
    static void Main(string[] args)
    {
        x = new Tumbler(10);
        y = new Tumbler(x, 20);
        while (true)
        {
            Console.WriteLine(x.Teeth + " " + y.Teeth);
            x.Actuate();
            Console.ReadKey();
        }
     }
}

This is the tumbler class - two event handlers that is automatically gets subscribed to when the property LinkedTumbler is filled.

It works as expected until the event is fired -- and "program terminated due to stack overflow"

public class Tumbler
{

    private const int DEFAULT_TEETH_MAX = 6;
    private const int DEFAULT_LOWEST_TEETHVAL = 1;
    private Tumbler linkedtumbler;
    private int current_Teeth;
    private int max_Teeth;
    private const int DEFAULT_TEETH = 1;

    public event EventHandler MaxTriggered;
    public event EventHandler MinTriggered;

    public Tumbler() : this(DEFAULT_TEETH_MAX)
    {

    }

    public Tumbler(int maxTeethValue, int currentTeeth = DEFAULT_TEETH)
    {
        MaxTeeth = maxTeethValue;
        Teeth = currentTeeth;
    }

    public Tumbler(Tumbler tbLink,  int maxTeethValue, int currentTeeth = DEFAULT_TEETH) :  this(maxTeethValue, currentTeeth)
    {
        LinkedTumbler = tbLink;
    }

    public int Teeth
    {
        get
        {
            return this.current_Teeth;
        }

        private set
        {
            if(value < DEFAULT_LOWEST_TEETHVAL)
            {
                if(MinTriggered != null)
                    MinTriggered(this, new EventArgs());
                this.current_Teeth = MaxTeeth;
            }
            else if (value <= MaxTeeth)
            {
                this.current_Teeth = value;
            }
            else
            {
                if (MaxTriggered != null)
                     MaxTriggered(this, new EventArgs());
                this.current_Teeth = DEFAULT_LOWEST_TEETHVAL;
            }
        }
    }

    public int MaxTeeth
    {
        get
        {
            return this.max_Teeth;
        }
        private set
        {
            this.max_Teeth = value;
        }
    }
    public Tumbler LinkedTumbler
    {
        get
        {
            return linkedtumbler;
        }

        private set
        {
            linkedtumbler = value;
            if (linkedtumbler.MaxTriggered == null)
                linkedtumbler.MaxTriggered += Linkedtumbler_MaxTriggered;
        }
    }

    private void Linkedtumbler_MaxTriggered(object sender, EventArgs e)
    {
        linkedtumbler.Actuate();
    }

    public void Actuate()
    {
        Teeth++;
    }

    public void ReverseActuate()
    {
        Teeth--;
    }
}

Upvotes: 0

Views: 67

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062695

At some point when x.Actuate() is called, it hits the:

            if (MaxTriggered != null)
                 MaxTriggered(this, new EventArgs());
            this.current_Teeth = DEFAULT_LOWEST_TEETHVAL;

region; so - it invokes the event via MaxTriggered, which is basically y.Linkedtumbler_MaxTriggered;; this calls straight back into linkedtumbler.Actuate();, which is effectively x.Actuate();. And recall that you haven't set this.current_Teeth = DEFAULT_LOWEST_TEETHVAL; yet (we haven't got that far), so nothing has changed - we're going to keep doing the same thing in a stack-dive until we explode.

Upvotes: 1

Related Questions