Search code examples
c#stack-overflow

StackOverflowException for no apparent reason.. This is really annoying


WHYYYYYYY?

The following is about half of my code, as I've deleted most of it along with every hair I lost while trying to solve this. No matter what I remove or change, I keep getting a StackOverflowException.

Which is extremely odd because this exact same code worked earlier.

Please give me any advice at all because I'm clueless...

I've checked this and I don't think this is what happening:

  • Infinite recursive loop
  • Program simply runs out of stack space

­

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;

namespace ConsoleApplication10
{
class Program
{
    public int currentDialogueID = 0;

    List<NPC> NPCList = new List<NPC>() {
            new NPC(0, "Man", 1, true),
            new NPC(1, "Woman", 1, true),
            new NPC(2, "Troll", 3, true)
        };

    static void Main(string[] args)
    {
        Program d = new Program();
        d.Init();
        Console.ReadKey(false);
    }

    void Init()
    {
        getNPCByName("Man").NPCDialogue();
    }

    public NPC getNPCByName(string npcName)
    {
        IEnumerable<NPC> myNPCsName = from nn in NPCList
                                      where nn._name.ToLower() == npcName.ToLower()
                                      orderby nn._name ascending
                                      select nn;

        foreach(NPC nn2 in myNPCsName)
        {
            return nn2;
        }

        return null;
    }

    public NPC getNPCByID(int npcID)
    {
        IEnumerable<NPC> NPCsByID = from ni in NPCList
                                    where ni._npcID == npcID
                                    orderby ni._npcID ascending
                                    select ni;

        foreach(NPC ni2 in NPCsByID)
        {
            return ni2;
        }

        return null;
    }

    public string getNPCNameByID(int npcid)
    {
        return getNPCByID(npcid)._name;
    }
}

class NPC : Program
{
    public string _name = "null";
    public int _level;
    public int _npcID;
    public int _maxDamage;
    public bool _canFight = false;

    public NPC(int npcID = 0, string name = "null", int level = 0, bool canSpeak = false, bool canFight = false, int maxDamage = 0)
    {
        _level = level;
        _name = name;
        _npcID = npcID;
        _canFight = canFight;
        _maxDamage = maxDamage;
    }

    public void NPCDialogue()
    {
        currentDialogueID = _npcID;
        switch(_npcID)
        {
            case 0:
            NPCSpeak("Man test... ... ...");
            break;

            case 1:
            NPCSpeak("Woman test");
            break;

            case 2:
            NPCSpeak("I'm Elad the Troll, Ramzes your ear is that of an elf");
            break;

            default:
            return;
        }
    }

    public void NPCSpeak(string text, int npcID = 99999)
    {
        if(npcID == 99999)
            npcID = currentDialogueID;
        if(npcID != 99999)
            type(getNPCNameByID(npcID) + ": " + text);
    }

    public void type(string x)
    {
        Random rnd = new Random();
        char[] xx = x.ToCharArray();
        for(int i = 0; i < xx.Length; i++)
        {
            Console.Write(xx[i]);
            System.Threading.Thread.Sleep(rnd.Next(10, 120));
            if(xx[i] == ':' || (xx[i] == '.' && xx[i - 1] != '.' && xx[i + 1] != '.') || xx[i] == '!' || xx[i] == '\n' || xx[i] == '?')
            {
                System.Threading.Thread.Sleep(rnd.Next(400, 1500));
            }
        }
    }
}

class Item : Program
{
    public string _name = "null";
    public string _description = "How did you get this?";
    public bool _isWeapon = false;
    public int _maxDamage;
    public int _itemID = 0;

    public Item(int itemID = 0, string name = "null", string description = "null", bool isWeapon = false, int maxDamage = 0)
    {
        _itemID = itemID;
        _name = name;
        _description = description;
        _isWeapon = isWeapon;
        _maxDamage = maxDamage;
    }
}
}

Solution

  • Looks like you're a little confused about what classes should be inherited where.

    Your program class creates a new list of 3 NPCs. NPC inherits from Program, which means (basically) that all the code from program is dropped into NPC. What this means here is that since Program creates a list of 3 NPCs when it's instantiated, NPC inherits this code and creates an additional list of 3 more NPCs, each of which inherits from program and create 3 more NPCs each, etc. until the stack overflows.

    The tip about looking at the call stack to catch this stuff is good advice. I'd also just add that inheritance is generally used slightly differently. Just because NPC and Item are used by your Program doesn't mean they have to (or should) inherit it. Inheritance is best used between classes where one is a subset of the other, but has more specific characteristics. A general example is that a class Animal with properties 'Family, Species, Age' etc. might be inherited by class Dog which also has all those properties, but you might also want to use the Dog-specific property 'Breed' as well.

    In your case NPC might be a parent class that is inherited by "Merchant" or "Companion", both of which are still NPCs (and therefore should have all the basic NPC characteristics) but might also have different behavior specific to their subclass. Item might be inherited by "Weapon" and "Shield", which are both items but have different additional characteristics to keep track of.