简体   繁体   English

Getter C#上的StackOverflowException

[英]StackOverflowException on Getter C#

I am getting a StackOverflowException on the get; 我在get上得到一个StackOverflowException get; of a property in an abstract class. 抽象类中的属性。

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

    }

I am setting and getting it here: 我正在设置并在此处获取:

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
}

One of those classes look like this: 其中一个类看起来像这样:

public class Movement : SnakeGame
{

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

To my knowledge a StackOverflowException means I somewhere have an an infinite loop or infinite recursion, but I honestly don't know where, nor do I know how to solve it. 据我所知,StackOverflowException意味着我在某个地方有一个无限循环或无限递归,但老实说我不知道​​在哪里,也不知道如何解决它。

This line in SnakeGame causes a recursion SnakeGame这一行会导致递归

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. 由于Movement继承自SnakeGame ,它的构造函数将初始化SnakeGame ,再次调用上面的行来初始化它自己的Movement字段。 That results into recursion. 这会导致递归。

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 . 如果调用Bad ,那么它将堆栈溢出,但大多数情况下溢出将报告为Good ,因为Good可能比使用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. 你需要做的是看看调用堆栈 ,因为这将是Good / Bad / Bad / Bad / Bad ...并且告诉你,这是Bad的是在做无限递归。 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 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". 您的构造函数正在设置SenseHatSnake所有子类之间共享的静态字段,这意味着最后一个类将字段设置为“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. 你也不能推导出Movement从构造类型的成员的类Movement作为其初始化的一部分。

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. 现在的子类GameObject份额SnakeGame对象来说,获得其属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM