Getter C#上的StackOverflowException

时间:2018-08-30 22:39:08

标签: c# uwp

我在抽象类中某个属性的get;上收到了StackOverflowException。

public abstract class SenseHatSnake
    {

        private readonly ManualResetEventSlim _waitEvent = new ManualResetEventSlim(false);

        protected SenseHatSnake(ISenseHat senseHat)
        {
            SenseHat = senseHat;
        }

        protected static ISenseHat SenseHat { get; set; } // This Line

        public virtual void Run()
        {
            throw new NotImplementedException();
        }

        protected void Sleep(TimeSpan duration)
        {
            _waitEvent.Wait(duration);
        }

    }

我正在这里设置并获得它:

public class SnakeGame : SenseHatSnake
{
    private readonly int _gameSpeed = 1000;
    private static Timer _updatePositionTimer;
    private bool _gameOver = false;

    public readonly Movement Movement = new Movement(SenseHat);
    public readonly Food Food = new Food(SenseHat);
    public readonly Body Body = new Body(SenseHat);
    public readonly Display Display = new Display(SenseHat);
    public readonly Draw Draw = new Draw(SenseHat);

    public SnakeGame(ISenseHat senseHat)
        : base(senseHat)
    {
    }
    //More code
}

其中一个类如下:

public class Movement : SnakeGame
{

    public Movement(ISenseHat senseHat)
        : base(senseHat)
    {
    }
    //More code
}

据我所知,StackOverflowException意味着我在某处具有无限循环或无限递归,但老实说,我不知道在哪里,也不知道如何解决它。

3 个答案:

答案 0 :(得分:12)

<xsl:for-each select="./*[local-name() = 'Application']/*[local-name() = 'Data']"> <xsl:if test=""> .... </xsl:if> </xsl:for-each> 中的这一行会导致递归

SnakeGame

由于public readonly Movement Movement = new Movement(SenseHat); 是从Movement继承的,因此其构造函数将初始化SnakeGame,再次调用上面的行以初始化自己的SnakeGame字段。导致递归。

答案 1 :(得分:5)

在其他答案中已经确定了溢出的根源,其他答案也指出了程序草图中的体系结构设计问题。

我想我会简要地说一下如何自己调试此类问题。

首先:面对堆栈溢出时,几乎总是存在无限的递归。如果在一个本来没有堆栈溢出的成员中报告了溢出,那发生了什么?这发生了:

npm install -g npm@latest

如果调用void Bad() { Good(); Bad(); } ,则它将堆栈溢出,但是大多数情况下,溢出将在Bad 中报告,因为Good可能使用< em>更多堆栈比对Good的任何单个调用都要多。

您需要做的是查看调用堆栈,因为它将是Bad,并且告诉您Good / Bad / Bad / Bad / Bad ...正在执行无限制的递归。 找到递归源的关键是找到直接或间接调用自己的东西。使用您可以使用的仪器进行操作;异常包含调用堆栈的痕迹。

答案 2 :(得分:2)

这是一个错误的模式:

protected SenseHatSnake(ISenseHat senseHat)
{
    SenseHat = senseHat;
}

protected static ISenseHat SenseHat { get; set; }
//        ^^^^^^

您的构造函数正在设置SenseHatSnake的所有子类之间共享的 static 字段,这意味着最后一个设置该字段的类“获胜”。这也意味着您永远无法设置该字段,因为要构造要分配给该字段的值,您必须创建一个必须设置该字段的对象-一条蛇追逐自己的尾巴。同样,您不能从构造Movement类型的成员的类派生Movement作为初始化的一部分。

解决此问题需要对您的课程进行认真的重组:

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
}

现在GameObject的子类共享SnakeGame对象,从而可以访问其属性。