抱歉,如果这是一个简单的问题; 这是我的第一语言,我正在尽我最大的努力寻找和遵循这个网站和其他的例子和解释。
我一直在尝试扩展一个创建“银行帐户”的Microsoft C#教程程序。 我正在尝试捕获和处理异常,特别是通过提示用户再次尝试获取有效的输入。
我遇到过这个线程和许多类似的线程,这些线程是关于在输入无效的情况下运行循环的,这个例子特别使用try/catch,如果我理解正确的话,它就是我想在这里使用的,因为我有几行代码可以抛出多个异常(它可以是非数值的,也可以是负值的)。 根据这些示例和其他示例,我不知道如何将初始余额输入分配给一个值,一旦输入有效,该值可以在循环之外引用(但仍然只能在CreateAccount方法内引用)。
我不确定当前的代码是否正常工作,但是当前这段代码会产生一个错误,因为在while循环之后,initBalInput没有被赋值,即使它是在循环之外声明的,并且是在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");
}
}
首先,我有两篇我认为必须阅读的关于异常处理的文章:
您不应该使用convert,而应该使用parse。 或者更好的tryparse()
。 字符串上的异常->; 数字转换是令人烦恼的例外的例子。
如果没有TryParse,我曾经为仍在研究框架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;
}
但该代码看起来像是您希望了解失败原因的详细信息。 在这一点上,您可能必须编写一个详细的catch块列表。
但是当前,此代码会产生错误,因为在while循环之后,initBalInput未被赋值,即使它是在循环之外声明的,并且是在try块中赋值的
问题是编译器不知道执行是否会到达try块:
while (valid == false)
在运行时计算。 您和我都知道,执行将至少进入一次while循环,因为valid
最初是false
,但编译器不会进入涉及变量的那种类型的分析,因此假定执行可能永远不会进入while循环,并且可以读取一个单元化的initbalinput
。
也就是说,您不应该养成使用Exeptions作为控制流机制的习惯。 异常应该是异常,不要把程序的逻辑建立在异常的基础上。 在您的示例中,应该研究Decimal.TryParse
方法。
还有,总是把你的问题分解成更小的问题。 一开始,从小处着手,做一个明显正确的线性方法。 在只有一两行长的方法中编写bug是非常困难的。
那你需要什么?
好吧,第一点:
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(RequestUser(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: ");