I am getting a StackOverflowException on the get;
of a property in an abstract class.
public abstract class SenseHatSnake
{
privat
The origin of the overflow has been identified in other answers, and other answers have pointed out the architectural design problems in your program sketch.
I thought I'd say briefly how to debug such issues yourself.
First: when faced with a stack overflow, there is almost always an unbounded recursion. When the overflow is reported in a member that plainly has no stack overflow, what has happened? This has happened:
void Bad()
{
Good();
Bad();
}
If Bad
is called then it will stack overflow, but most of the time the overflow will be reported in Good
, because Good
probably uses more stack than any single call to Bad
.
What you need to do is look at the call stack, because it will be Good / Bad / Bad / Bad / Bad ...
and that tells you that it is Bad
that is doing the unbounded recursion. The key to finding the source of a recursion is to find the thing that is actually calling itself, directly or indirectly. Use the instrumentation at your disposal to do so; the exception contains a trace of the call stack.
This line in SnakeGame
causes a recursion
public readonly Movement Movement = new Movement(SenseHat);
Since Movement
is inherited from SnakeGame
, its constructor will initialize SnakeGame
, calling the line above again to initialize its own Movement
field. That results into recursion.
This is a bad pattern:
protected SenseHatSnake(ISenseHat senseHat)
{
SenseHat = senseHat;
}
protected static ISenseHat SenseHat { get; set; }
// ^^^^^^
Your constructor is setting a static field shared among all subclasses of SenseHatSnake
, meaning that the last class setting the field "wins". It also means that you can never set this field, because in order to construct the value to assign to the field you must create an object that has to have that field set - a snake chasing its own tail. Also you cannot derive Movement
from a class that constructs a member of type Movement
as part of its initialization.
Fixing this requires some serious re-organization of your classes:
public class SnakeGame {
private readonly int _gameSpeed = 1000;
private static Timer _updatePositionTimer;
private bool _gameOver = false;
public Movement Movement {get;}
public Food Food {get;}
public Body Body {get;}
public Display Display {get;}
public Draw Draw {get;}
public SnakeGame(ISenseHat senseHat)
{
Movement = new Movement(this);
Food = new Food(this);
Body = new Body(this);
Display = new Display(this);
Draw = new Draw(this);
}
//More code
}
public abstract class GameObject {
protected readonly SnakeGame game;
protected GameObject(SnakeGame game) {
this.game = game;
}
}
public class Movement : GameObject
{
public Movement(SnakeGame game)
: base(senseHat)
{
}
//More code
}
Now subclasses of GameObject
share SnakeGame
object, gaining access to its properties.