为什么在不应该抛出该异常时抛出该异常?
Why Is This Exception Thrown When it Shouldn't Be?
我有以下(非常简单的)控制台计算器,可以进行基本的圆计算:
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,程序终止。
然而,有两个基本问题:
- 如果用户选择按Y进行另一次计算,程序会提示用户输入一个值,但也会执行catch块并抛出异常。这显示在示例输出中:
Enter the radius of the circle: 3
A circle whose radius is 3 has the following properties:
Area: 28.27
Circumference: 18.85
Diameter: 6
Do you wish to make another calculation [Y or N]? Y
Enter the radius of the circle: [Error] Input string was not in a correct format.
Enter the radius of the circle:
- 第二个问题是当用户输入 Y 或 N 以外的内容时,程序也会出现意外行为,如输出所示:
- Enter the radius of the circle: 4
- A circle whose radius is 4 has the following properties:
- Area: 50.27
- Circumference: 25.13
- Diameter: 8
- Do you wish to make another calculation [Y or N]? j Invalid choice! Press Y to continue or N to exit.
- Do you wish to make another calculation [Y or N]? Invalid choice! Press Y to continue or N to exit.
- Do you wish to make another calculation [Y or N]? Invalid choice! Press Y to continue or N to exit.
- Do you wish to make another calculation [Y or N]?
我似乎无法弄清楚为什么会发生这两种情况。我怀疑这是我使用 goto
和 continue
,但我说不出来。
问题在于您使用了 Read()
和 ReadLine()
,以及如何将输入从 shell 发送到 Console
对象。
在控制台对象中,输入流(缓冲区)仅在按下 [Enter] 后加载。那时,Read()
将 return 字符串中的下一个未读字符,但 只有那个字符 。当随后调用 ReadLine()
时,它会转到换行符仍在等待的缓冲区,因此它立即 returns (在这种情况下)一个空字符串。随之而来的是欢闹。
补救留作 reader 的练习;)
问题是你的Convert.ToChar(Console.Read())
。它从输入中读取一个字符,但在按下回车之前不会从控制台设置输入。所以 Console.Read()
正确地得到 'Y'
,但是输入有一个 ENTER 排队,所以你的 Convert.ToDouble(Console.ReadLine())
得到一个它试图转换的空字符串因此例外。
将 Convert.ToChar(Console.Read())
更改为 Convert.ToChar(Console.ReadLine())
,它工作正常。
您还应该摆脱 goto
s 并摆脱异常陷阱 - 您应该改用 double.TryParse(...)
。没有更多例外。
我重构了您的代码让您尝试 - 没有 goto
s 也没有异常处理。
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();
我有以下(非常简单的)控制台计算器,可以进行基本的圆计算:
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,程序终止。
然而,有两个基本问题:
- 如果用户选择按Y进行另一次计算,程序会提示用户输入一个值,但也会执行catch块并抛出异常。这显示在示例输出中:
Enter the radius of the circle: 3
A circle whose radius is 3 has the following properties:
Area: 28.27
Circumference: 18.85
Diameter: 6
Do you wish to make another calculation [Y or N]? Y
Enter the radius of the circle: [Error] Input string was not in a correct format.
Enter the radius of the circle:
- 第二个问题是当用户输入 Y 或 N 以外的内容时,程序也会出现意外行为,如输出所示:
- Enter the radius of the circle: 4
- A circle whose radius is 4 has the following properties:
- Area: 50.27
- Circumference: 25.13
- Diameter: 8
- Do you wish to make another calculation [Y or N]? j Invalid choice! Press Y to continue or N to exit.
- Do you wish to make another calculation [Y or N]? Invalid choice! Press Y to continue or N to exit.
- Do you wish to make another calculation [Y or N]? Invalid choice! Press Y to continue or N to exit.
- Do you wish to make another calculation [Y or N]?
我似乎无法弄清楚为什么会发生这两种情况。我怀疑这是我使用 goto
和 continue
,但我说不出来。
问题在于您使用了 Read()
和 ReadLine()
,以及如何将输入从 shell 发送到 Console
对象。
在控制台对象中,输入流(缓冲区)仅在按下 [Enter] 后加载。那时,Read()
将 return 字符串中的下一个未读字符,但 只有那个字符 。当随后调用 ReadLine()
时,它会转到换行符仍在等待的缓冲区,因此它立即 returns (在这种情况下)一个空字符串。随之而来的是欢闹。
补救留作 reader 的练习;)
问题是你的Convert.ToChar(Console.Read())
。它从输入中读取一个字符,但在按下回车之前不会从控制台设置输入。所以 Console.Read()
正确地得到 'Y'
,但是输入有一个 ENTER 排队,所以你的 Convert.ToDouble(Console.ReadLine())
得到一个它试图转换的空字符串因此例外。
将 Convert.ToChar(Console.Read())
更改为 Convert.ToChar(Console.ReadLine())
,它工作正常。
您还应该摆脱 goto
s 并摆脱异常陷阱 - 您应该改用 double.TryParse(...)
。没有更多例外。
我重构了您的代码让您尝试 - 没有 goto
s 也没有异常处理。
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();