实现一个 while 循环来检查输入有效性中的多个异常



对不起,如果这是一个简单的问题;这是我的第一语言,我正在尽力寻找并遵循本网站上的示例和解释。

我一直在尝试扩展一个创建"银行账户"的Microsoft C# 教程程序。我正在尝试捕获和处理异常,特别是通过提示用户重试有效输入。

我遇到了这个线程和许多关于在输入无效时运行循环的类似线程,这个例子专门使用 try/catch,如果我理解正确的话,这就是我想在这里使用的,因为我有几行代码可能会抛出多个异常(它可能是非数字的,也可能是负数(。按照这些和其他示例,一旦输入有效,我无法弄清楚如何将初始余额输入分配给我可以在循环外部引用的值(但仍然只能在 CreateAccount 方法中引用(。

我不确定我目前的工作是什么,但目前这段代码会产生一个错误,因为 initBalInput 在 while 循环后未分配,即使它在循环外声明并在 try 块中分配。

public static void CreateAccount()
{

// Prompt for BankAccount constructor parameter {name} which is passed to BankAccount.Owner in constructor
Console.WriteLine("Name on new account: ");
string nameInput = Console.ReadLine();
decimal initBalInput;
bool valid = false;
while (valid == false)
{
try
{
Console.WriteLine("How much to deposit for initial balance: ");
initBalInput = Convert.ToDecimal(Console.ReadLine());
}
catch (ArgumentOutOfRangeException)
{
Console.WriteLine("Initial balance must be positive!");
valid = false;
continue;
}
catch (FormatException)
{
Console.WriteLine("Initial balance must be a number!");
valid = false;
continue;
}
valid = true;
}
// Create new instance "account" of type BankAccount and set its parameters
BankAccount account = new BankAccount(nameInput, initBalInput);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");
}

不要捕获异常,而是编写处理无效输入的代码。

public static void CreateAccount()
{

// Prompt for BankAccount constructor parameter {name} which is passed to BankAccount.Owner in constructor
Console.WriteLine("Name on new account: ");
string nameInput = Console.ReadLine();
string initBalInput = Console.ReadLine();
// try parse will check for invalid decimal values and also, positive values can be checked
if(decimal.TryParse(initBalInput, out decimal initBal) && initBal > 0) {
// Create new instance "account" of type BankAccount and set its parameters
BankAccount account = new BankAccount(nameInput, initBal);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");

} else {
Console.WriteLine("Invalid initial balance");
}
}

但目前此代码会产生错误,因为 initBalInput 在 while 循环后未赋值,即使它在循环外声明并在 try 块中赋值

问题是编译器不知道执行是否会到达try块:

while (valid == false)

在运行时进行评估。你和我都知道执行将至少进入一次 while 循环,因为最初validfalse但编译器不会进入涉及变量的那种类型的分析,因此假设执行可能永远不会进入 while 循环并且可以读取单位化initBalInput

也就是说,您不应该养成使用exepctions作为控制流机制的习惯。异常应该是例外,不要将程序的逻辑建立在异常的基础上。在您的情况下,您应该研究方法decimal.TryParse.

此外,始终将您的问题分解为较小的问题。一开始,从小处着手,做一个明显正确的衬里方法。在一两行长的方法中编写错误非常困难。

那你需要什么?

  1. 提示用户输入的方法。
  2. 验证输入的方法
  3. 要求用户在输入错误时重试的内容。

好的,数字一:

static string RequestUserInput(string message)
{
Console.Write(message);
return Console.ReadLine();
}

第二:我们已经有了decimal.TryParse(string, out decimal d)。如果输入字符串可以解析为有效的十进制数,此方法将返回true,该十进制数将分配给d,否则false

第三:

public static decimal GetDecimalInput(string message)
{
decimal d;
while (true)
{
if (!decimal.TryParse(RequestUserInput(message), out d))
//tryparse failed, input is not a valid decimal number
Console.WriteLine("Initial balance must be a number!");
else if (d < 0) //try parse succeeded, we know input is a valid
// decimal number d but it might be negative.
Console.WriteLine("Initial balance must be positive!");
else
//we know inout is a valid non negative decimal number.
//break out of the loop, we don't need to ask again.
break;
}
return d;
}

现在,你把它们放在一起:

var accountBalance = GetDecimalInput("How much to deposit for initial balance: ");

首先,我有两篇关于异常处理的文章,我认为这是必读的:

  1. 这有助于对 4 种常见的异常类型进行分类 - 如果您甚至应该考虑捕获它们。
  2. 虽然这个详细介绍了良好做法。

您不应该使用转换,而是解析。甚至更好的TryParse().字符串 -> 数字转换上的异常是令人烦恼的异常的示例。

如果没有 TryParse,我曾经为仍在使用 Framework 1.1 的人编写了 Int.TryParse(( 的自定义实现:

//Parse throws ArgumentNull, Format and Overflow Exceptions.
//And they only have Exception as base class in common, but identical handling code (output = 0 and return false).
bool TryParse(string input, out int output){
try{
output = int.Parse(input);
}
catch (Exception ex){
if(ex is ArgumentNullException ||
ex is FormatException ||
ex is OverflowException){
//these are the exceptions I am looking for. I will do my thing.
output = 0;
return false;
}
else{
//Not the exceptions I expect. Best to just let them go on their way.
throw;
}
}
//I am pretty sure the Exception replaces the return value in exception case. 
//So this one will only be returned without any Exceptions, expected or unexpected
return true;
}

但是该代码看起来您希望获得失败原因的详细信息。此时,您可能需要编写捕获块的详细列表。

最新更新