递归调用引发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
相关产品推荐
相关产品推荐

