带有类实例的堆栈溢出异常

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带有类实例的堆栈溢出异常相关的知识,希望对你有一定的参考价值。

在我的Main Menu类中,当用户键入要转到sell菜单的数字时,我有一个switch语句,它调用sell菜单类中的DisplaySellMenu方法(在主菜单类中创建了sell菜单类的实例)。然后我在Sell Menu类中创建了一个新的Main菜单类实例,在下面你可以看到我所做的switch语句,这样当用户选择退出到Main Menu时它会调用MainMenu类中的DisplayMainMenu方法,这样用户就可以了可以回到MainMenu。这导致类的实例之间出现堆栈溢出异常。如何在允许用户退回主菜单的同时阻止这种情况发生?

主菜单类:

class MainMenu
{
    public BuyMenu buyMenu = new BuyMenu();
    public SellMenu sellMenu = new SellMenu();
    public ShipGarage shipGarage = new ShipGarage();
    int Exit = 0;

    public void DisplayMenu()
    {           
        Console.WriteLine("Whatcha tryin to do yo?");
        Console.WriteLine("Type 1 to buy");                  
        Console.WriteLine("Type 2 to sell");                 
        Console.WriteLine("Type 3 for SpaceShip Upgrade ");                  
        Console.WriteLine("Type 4 to quit game");
        int userSelection = int.Parse(Console.ReadLine());

        do
        {
            switch (userSelection)
            {                
                case 1:
                    buyMenu.DisplayInventory(buyMenu);
                    DisplayMenu();
                    break;

                case 2:
                    sellMenu.SoldItems();
                    DisplayMenu();
                    break;

                case 3:
                    shipGarage.DisplayGarage(shipGarage);
                    DisplayMenu();
                    break;

                case 4:
                    Exit += 1;
                    break;

                default:
                    Console.WriteLine("Invalid Input");
                    break;
            }
        } while (Exit == 1);



    }
}

卖菜单类:

class SellMenu
{

    static Random rnd = new Random();
    MoneyMath Money = new MoneyMath();
    MainMenu MainMenu = new MainMenu();
    int goldPrice = rnd.Next(100, 1001);
    int silverPrice = rnd.Next(100, 1001);
    int titaniumPrice = rnd.Next(100, 1001);
    int Exit = 0;


    public string DisplayInventory()
    {
        Console.WriteLine("What would you like to sell?");
        Console.WriteLine("Type 1 for Gold");
        Console.WriteLine("Type 2 for Silver");
        Console.WriteLine("Type 3 for Titanium");
        Console.WriteLine("Type 4 for Main Menu");

        string itemList = "Gold"     + "   " + "$" + (goldPrice)   + "
" +
                          "Silver"   + "   " + "$" + (silverPrice) + "
" +
                          "Titanium" + "   " + "$" + (titaniumPrice);

        Console.WriteLine(itemList);
        return itemList;
    }

    public void SoldItems()
    {
        do
        {
            DisplayInventory();
            int userSelection = int.Parse(Console.ReadLine());
            switch (userSelection)
            {
                case 1:
                    Money.MoneyAddition(goldPrice, 1);
                    Console.WriteLine(Money.userMoney);
                    break;
                case 2:
                    Money.MoneyAddition(silverPrice, 1);
                    Console.WriteLine(Money.userMoney);
                    break;
                case 3:
                    Money.MoneyAddition(titaniumPrice, 1);
                    Console.WriteLine(Money.userMoney);
                    break;
                case 4:
                    Exit += 1;
                    MainMenu.DisplayMenu();
                    break;
                default:
                    Console.WriteLine("Invalid Input");
                    break;
            }
        } while (Exit == 1);
    }
}
答案

在我看来,你的SoldItems()案例4应该只是这样:

case 4:
    return;

你已经在SoldItems()DisplayMenu()调用了MainMenu,所以你需要做的就是返回DisplayMenu() switch语句并继续循环。

这里不需要Exit变量,因为return将离开整个方法体,终止while循环。这同样适用于DisplayMenu()Exit变量。

SoldItems()的完整代码:

public void SoldItems()
{
    do
    {
        DisplayInventory();
        int userSelection = int.Parse(Console.ReadLine());
        switch (userSelection)
        {
            case 1:
                Money.MoneyAddition(goldPrice, 1);
                Console.WriteLine(Money.userMoney);
                break;
            case 2:
                Money.MoneyAddition(silverPrice, 1);
                Console.WriteLine(Money.userMoney);
                break;
            case 3:
                Money.MoneyAddition(titaniumPrice, 1);
                Console.WriteLine(Money.userMoney);
                break;
            case 4:
                return;
            default:
                Console.WriteLine("Invalid Input");
                break;
        }
    }
    while (true);
}

StackoverflowException的解释:

堆栈变满时会引发此异常。想象一下,你有三种方法:

public void A() { B(); }
public void B() { C(); }
public void C() { }

当A调用B时,额外的层被压入堆栈。当B调用C时也会发生同样的情况。当C返回到B时,该层被推离堆栈,然后相同,然后B返回到A.

.NET堆栈的大小有限,因此您无法无限地调用方法。对于您编写的任何代码,这通常都足够大,除了递归函数可能有点危险。想象一下这段代码:

public void A() { A(); }

它永远地称自己为递归。此代码注定会遇到Stackoverflow异常。当你编写这样的代码时,你需要对它进行限制,以确保它只是如此深入。例:

public void A(int maxDepth = 0) { if (maxDepth < 5) { A(++maxDepth); } }

您可以阅读有关堆栈和here此异常的更多信息。

Obligatory Google Easter egg

以上是关于带有类实例的堆栈溢出异常的主要内容,如果未能解决你的问题,请参考以下文章

C# 捕获堆栈溢出异常

声明大数组时出现堆栈溢出异常

声明大数组时出现堆栈溢出异常

如何在 x64 上制作“堆栈溢出”异常

带有尾递归函数c ++的堆栈溢出

手势捕获的异常:堆栈溢出