You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归调用引发System.StackOverflowException,如何优化自动属性掷骰器?

解决自动属性掷骰器的栈溢出问题

嗨,我明白你遇到的问题了——递归调用确实会在连续多次没掷出18的时候把调用栈撑爆,最终抛出System.StackOverflowException。让我给你拆解一下问题根源,再提供可行的解决方案:

问题根源

每次生成的属性里没有18时,你都会递归调用Main(null),这意味着每一次失败的尝试都会在调用栈上新增一个方法调用帧。当尝试次数足够多(比如连续几百上千次没出18),栈空间就会被耗尽,触发栈溢出异常。递归在这里不是合适的选择,因为我们无法预测需要多少次尝试才能得到18,迭代(循环)才是更安全的方式。

解决方案:用循环代替递归

我们可以把递归逻辑改成循环结构,这样每次尝试都不会累积栈帧,彻底避免栈溢出。同时还能顺便优化代码的可读性,比如用列表来存储属性,而不是单独的6个变量。

优化后的完整代码

class Program {
    // 静态Random实例,只初始化一次,避免重复随机序列
    private static Random _rnd = new Random();

    static void Main(string[] args) {
        // 循环尝试,直到生成包含18的属性组合
        while (true) {
            if (GenerateAndCheckStats()) {
                break; // 成功生成,退出循环
            }
        }
    }

    static bool GenerateAndCheckStats() {
        List<int> stats = new List<int>();

        for (int i = 0; i < 6; i++) {
            // 掷4个D6,去掉最小的一个,求和得到属性值
            List<int> rolls = new List<int> {
                _rnd.Next(1,7),
                _rnd.Next(1,7),
                _rnd.Next(1,7),
                _rnd.Next(1,7)
            };
            rolls.Sort();
            rolls.RemoveAt(0); // 移除最小的点数
            stats.Add(rolls.Sum());
        }

        // 检查是否有属性等于18
        if (stats.Contains(18)) {
            // 输出所有属性
            foreach (int stat in stats) {
                Console.WriteLine(stat);
            }
            return true;
        }
        return false;
    }
}

关键修改点说明

  • 替换递归为循环:用while(true)在Main里重复调用属性生成方法,直到得到符合条件的结果。循环不会在栈上累积调用帧,完全避免栈溢出。
  • 使用静态Random实例:原代码每次生成属性时都会新建Random,如果调用间隔极短,会导致随机种子重复,生成相同的随机序列。把Random设为类的静态字段,只初始化一次,能保证随机数的均匀性。
  • 简化属性存储:用List<int>存储6个属性,比单独的stat1到stat6更简洁,也方便用Contains(18)快速检查是否有符合条件的属性。

这样修改后,程序就能稳定运行,直到生成包含18的属性组合,再也不会出现栈溢出问题了。

内容的提问来源于stack exchange,提问作者Kev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:17:12