为什么在不应该抛出此异常时引发此异常

本文关键字:异常 不应该 为什么 | 更新日期: 2023-09-27 18:36:13

我有以下(非常简单的)控制台计算器,可以进行基本的圆计算:

using System;
namespace Circle
{
    class Program
    {
        /* Compute the area of a cricle given its radius. */
        public static double Area(double radius)
        {
            return Math.Pow(radius, 2) * Math.PI;
        }
        /* Compute the circumference of a circle given is radius. */
        public static double Circumference(double radius)
        {
            return radius * 2 * Math.PI;
        }
        /* Compute the diameter of a circle given its radius. */
        public static double Diameter(double radius)
        {
            return radius * 2;
        }
        /* Report the result. */
        public static string Result(double radius, double area, double circumference, double diameter)
        {
            return "- A circle whose radius is " + radius + " has the following properties: "
                    + "'n- Area: " + area.ToString("0.##") + "'n- Circumference: " + circumference.ToString("0.##")
                    + "'n- Diameter: " + diameter.ToString("0.##");
        }
        static void Main(string[] args)
        {
            double radius = 0;
            char choice;
            while (true)
            {
            Calculate:
                {
                    // 1. Get the radius from the user. 
                    Console.Write("- Enter the radius of the circle: ");
                    try
                    {  // verify the input is of numerical type 
                        radius = Convert.ToDouble(Console.ReadLine());
                        if (radius <= 0)  // check for negative values 
                        {
                            Console.WriteLine(" [Error] Radius must be a positive value!");
                            Console.WriteLine();
                            continue;  // restart from the next iteration without executing the rest of the statements 
                        } // end if 
                    }
                    catch (FormatException e)
                    {
                        Console.WriteLine(" [Error] " + e.Message);
                        Console.WriteLine(); // skip a line
                        continue;  // restart from the next iteration without executing the rest of the statements 
                    } // end catch 
                }
                // 2. Calculate the area, circumference, and diameter of the circle. 
                double area = Area(radius);
                double circumference = Circumference(radius);
                double diameter = Diameter(radius);
                // 3. Display the results. 
                Console.WriteLine(Result(radius, area, circumference, diameter));
            // 4. Ask the user whether to quit.
            Ask:
                {
                    Console.Write("- Do you wish to make another calculation [Y or N]? ");
                    choice = Convert.ToChar(Console.Read());
                }
                if (choice.Equals('Y') || choice.Equals('y'))
                {
                    goto Calculate; // return to the beginning of the Calculate block. 
                }
                else if (choice.Equals('N') || choice.Equals('n'))
                {
                    break; // exit 
                }
                else {
                    Console.WriteLine("Invalid choice! Press Y to continue or N to exit.");
                    goto Ask; // return to the beginning of the Ask block. 
                }
            }  // end while 
            Console.WriteLine("Thank you for using me. Have a nice day!");
            Console.WriteLine();
        } // end Main 
    }
}
计算

后,程序会询问用户是否希望进行另一次计算。如果用户输入 Y,程序会提示他们再次输入半径。如果用户输入 N,程序将终止。

但是,有两个基本问题:

  1. 如果用户选择通过按 Y 进行另一次计算,程序会提示用户输入值,但也会执行 catch 块并引发异常。这显示在示例输出中:
  • 输入圆的半径:3

  • 半径为 3 的圆具有以下属性:

  • 面积: 28.27

  • 周长:18.85

  • 直径: 6

  • 是否要进行其他计算 [Y 或 N]?Y

  • 输入圆的半径:[错误] 输入字符串的格式不正确。

  • 输入圆的半径:

  1. 第二个问题是,当用户输入 Y 或 N 以外的内容时,程序也会显示意外行为,如输出所示:
  • 输入圆的半径:4
  • 半径为 4 的圆具有以下属性:
  • 面积: 50.27
  • 周长:25.13
  • 直径: 8
  • 是否要再进行一次计算 [Y 或 N]? j 选择无效!按 Y 继续或按 N 退出。
  • 是否要进行其他计算 [Y 或 N]?选择无效!按 Y 继续或按 N 退出。
  • 是否要进行其他计算 [Y 或 N]?选择无效!按 Y 继续或按 N 退出。
  • 是否要进行其他计算 [Y 或 N]?

我似乎无法弄清楚为什么会发生这两种情况。我怀疑这是我使用gotocontinue,但我说不出来。

为什么在不应该抛出此异常时引发此异常

问题是你的Convert.ToChar(Console.Read())。这会从输入中读取字符,但在按下 Enter 之前不会从控制台设置输入。因此,Console.Read()正确获取'Y',但输入有一个 ENTER 排队,因此您的Convert.ToDouble(Console.ReadLine())会获得一个空字符串,它尝试转换该字符串,因此会出现异常。

Convert.ToChar(Console.Read())更改为Convert.ToChar(Console.ReadLine()),它工作正常。

您还应该摆脱goto s并摆脱异常捕获 - 您应该改用double.TryParse(...)。没有更多的例外。


我对您的代码进行了重构供您尝试 - 没有goto,也没有异常处理。

while (true)
{
    while (true)
    {
        Console.Write("- Enter the radius of the circle: ");
        double radius;
        if (double.TryParse(Console.ReadLine(), out radius) && radius > 0.0)
        {
            double area = Area(radius);
            double circumference = Circumference(radius);
            double diameter = Diameter(radius);
            Console.WriteLine();
            Console.WriteLine(Result(radius, area, circumference, diameter));
            break;
        }
        Console.WriteLine(" [Error] Radius must be a positive value!");
        Console.WriteLine();
    }
    string choice = "";
    while (true)
    {
        Console.Write("- Do you wish to make another calculation [Y or N]? ");
        choice = Console.ReadLine();
        if (new [] { "Y", "N", }.Contains(choice.ToUpper()))
        {
            break;
        }
        Console.WriteLine();
        Console.WriteLine("- Invalid choice! Press Y to continue or N to exit.");
    }
    if (choice.ToUpper() == "N")
    {
        break;
    }
    Console.WriteLine();
}
Console.WriteLine();
Console.WriteLine("- Thank you for using me. Have a nice day!");
Console.WriteLine();

问题在于你对Read()ReadLine()的使用,以及输入是如何从 shell 发送到Console对象的。

在控制台对象中,输入流(缓冲区)仅在按下 [Enter] 后加载。 此时,Read()将返回字符串中的下一个未读字符,但仅返回该字符。 当随后调用ReadLine()时,它会转到换行符仍在等待的缓冲区,因此它会立即返回(在本例中)一个空字符串。 热闹随之而来。

修复留给读者练习;)