【问题标题】:Why Is This Exception Thrown When it Shouldn't Be?为什么不应该抛出这个异常?
【发布时间】:2016-02-26 03:15:29
【问题描述】:

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

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]?是的

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

  • 输入圆的半径:

  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,但我说不出来。

【问题讨论】:

  • 你真的不应该使用goto。这很糟糕。
  • 感谢您的评论。我知道这不是最好的主意,但在这种情况下似乎很有意义。如果您有其他建议或替代方案,请随时告诉我。
  • 函数将是比goto 语句更优雅的解决方案

标签: c# exception console-application


【解决方案1】:

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

Convert.ToChar(Console.Read())改成Convert.ToChar(Console.ReadLine())就可以了。

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


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

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

【讨论】:

  • 这完全解决了它。我承认,我对 ReadLine() 和 Read() 之间区别的理解是初步的。毫不奇怪我在那里做了什么!谢谢!
  • 只是对重构版本的提醒:我将它复制到我的 IDE 中进行测试,但它告诉我没有“包含”方法,因此它给了我一个错误.我在 VS 2015 中使用 C# 6.0。(不过,我得到了修改后程序背后的一般逻辑。)
  • 我认为您需要对 System.Linq 的引用才能使 .Contains 工作。
【解决方案2】:

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

在 Console 对象中,输入流(缓冲区)只有在按下 [Enter] 后才会加载。此时,Read() 将返回字符串中的下一个未读字符,但只返回那个字符。当随后调用ReadLine() 时,它会转到换行符仍在等待的缓冲区,因此它立即返回(在这种情况下)一个空字符串。欢闹随之而来。

补救留给读者作为练习;)

【讨论】:

  • 如果你的作业是指我作为 C# 初学者为自己设计的问题,那么你是对的。感谢您的意见!
  • 很公平!我记得我自己也对几种语言做过同样的事情。因此编辑。
  • 不用担心。再次感谢你:)
猜你喜欢
  • 2014-07-09
  • 1970-01-01
  • 1970-01-01
  • 2017-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多