在下面的有效代码中,我想处理5种可能由用户输入创建的异常。
我知道我应该使用IF
语句来处理这些异常,但是要求是使用异常处理程序来处理错误。因此,我只想在此方面寻求输入,而不是其他选择。
我想用异常处理程序来处理它们。
我遇到的问题是在哪里放置异常处理代码。
同样,我也有5个要检查的异常,这是否意味着我需要5个不同的try/catch
块,还是可以在同一个块中全部处理?
我要寻找的例外情况是,尝试创建19个以上的帐户,尝试创建初始余额低于$300
的帐户,从帐户中提取比当前余额更多的金额,并尝试在未创建的帐户,并在TextBox
中输入数字以外的任何内容。
因此,如果用户犯了这些错误之一,我想抛出该错误并向用户显示错误信息。
非常感谢您的协助。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MoreRobustBankGUI
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private int _nextIndex = 0;
List<Account> accounts = new List<Account>();
decimal balance = 0;
private void createButton1_Click(object sender, EventArgs e)
{
if (accounts.Count < 19 && balance > 300)
{
_nextIndex++;
int accountId = _nextIndex;
decimal.TryParse(amountTextBox2.Text, out balance);
transactionLabel3.Text = "Account: #" + accountId + " created with a starting balance of $" + balance;
accountTextBox1.Text = "" + accountId;
accounts.Add(new Account(balance)
{
AccountId = accountId
});
}
else
{
transactionLabel3.Text = "Can only create up to 19 accounts and starting balance must be $300";
}
}
private void executeButton2_Click(object sender, EventArgs e)
{
decimal amount = 0;
int accountID;
string textAmount = amountTextBox2.Text == "" ? "0" : amountTextBox2.Text;
if (depositRadioButton3.Checked == true)
{
if (string.IsNullOrEmpty(accountTextBox1.Text)) return;
bool accountCanBeConverted = int.TryParse(accountTextBox1?.Text, out accountID);
bool ammountCanBeConverted = decimal.TryParse(amountTextBox2?.Text, out amount);
if (accountCanBeConverted && ammountCanBeConverted && amount > 0)
{
var selectedAccount = GetAccount(accountID);
selectedAccount.DepositFunds(amount);
transactionLabel3.Text = $"Account: #{selectedAccount.AccountId} You made a deposit of ${amount}";
}
}
else if (withdrawRadioButton2.Checked == true)
{
if (string.IsNullOrEmpty(accountTextBox1.Text)) return;
bool accountCanBeConverted = int.TryParse(accountTextBox1?.Text, out accountID);
bool ammountCanBeConverted = decimal.TryParse(amountTextBox2?.Text, out amount);
if (accountCanBeConverted && ammountCanBeConverted && amount > 0)
{
var selectedAccount = GetAccount(accountID);
if (selectedAccount.HasAvailableFunds)
{
selectedAccount.WithdrawFromAccount(amount);
transactionLabel3.Text = $"Account: #{selectedAccount.AccountId} You made a withdrawal of ${amount}";
}
else
{
transactionLabel3.Text = $"Account: #{selectedAccount.AccountId} Does not have available funds to withdraw";
}
}
}
else if (balanceRadioButton3.Checked == true)
{
if (string.IsNullOrEmpty(accountTextBox1.Text)) return;
bool accountCanBeConverted = int.TryParse(accountTextBox1?.Text, out accountID);
var selectedAccount = GetAccount(accountID);
var balance = selectedAccount.GetAvailableBalanceForAccount(accountID);
if (balance == -1234567890)
{
transactionLabel3.Text = $"Invalid account number passed.";
}
else
{
transactionLabel3.Text = $"Account: #{selectedAccount.AccountId} Balance: $ {selectedAccount.GetAvailableBalanceForAccount(accountID)}";
}
}
clearFields();
}
public void clearFields()
{
amountTextBox2.Text = "";
}
public Account GetAccount(int id)
{
return accounts.Where(x => x.AccountId == id).FirstOrDefault();
}
public class Account
{
public Account(decimal balance)
{
Balance = balance;
}
public int AccountId { get; set; }
public decimal Balance { get; set; }
public void WithdrawFromAccount(decimal deductionAmount)
{
Balance -= deductionAmount;
}
public void DepositFunds(decimal depositAmount)
{
Balance += depositAmount;
}
public bool HasAvailableFunds => Balance > 0;
public decimal GetAvailableBalanceForAccount(int accountId)
{
if (accountId == AccountId)
{
return Balance;
}
else
{
return -1234567890;
}
}
}
}
}
答案 0 :(得分:3)
抱歉,这是一个“不要那样做”的答案...
将异常用于“正常”业务控制流不是一个好习惯。例外事件应该例外。
人们创建余额太少的帐户,并且尝试(无论如何对我来说)尝试提取比他们帐户中更多的余额是很正常的。这些错误应由常规控制流((if balance < MIN_BALANCE)
类型的事物)处理。
对于前进的方式,可能会调查违反业务规则的情况。 您可以通过多种方式来执行此操作...这是您可以尝试的简单方法。 https://softwareengineering.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why
答案 1 :(得分:1)
我同意这是一个糟糕的主意,希望您真的知道自己在做什么。正确的异常处理是我的烦恼,您的想法听起来很难。这是我认为必须阅读并链接很多的两篇文章:
https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/
https://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
总而言之,有人曾经有一个问题,因为他在.NET 1.1上运行,因此无法使用TryParse。因此,我很快就共同尝试了这个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;
}
我认为问题(处理方式完全相同的非常不同的异常)与您的问题相同。
答案 2 :(得分:1)
尽管我完全同意@Loofer的回答(对此表示+1)。
似乎您有不同的用例。
因此给出答案
我也有5个要检查的异常,这是否意味着我 需要5个不同的try / catch块,或者我可以在同一时间处理它们 阻止?
您应该使用Multiple Catch块
类似的东西
try
{
//
}
catch(Type1Exception exception)
{
}
catch(Type2Exception exception)
{
}
catch(Type3Exception exception)
{
}
等等。
但是还有另一种方式可以回答您的两个问题。
这也是个人建议,那就是创建一个类似这样的辅助方法
private void HandleCustomException(Exception exception)
{
// Your Error Handling Code goes here
if(exception is Type1Exception)
{...}
...
}
然后将单独的try catch放入您的click事件中,这会将接收到的所有异常发送到此辅助方法
类似的东西
private void createButton1_Click(object sender, EventArgs e)
{
try
{
if(Your Condition)
{
throw new Type1Exception();
}
}
catch(Exception exception)
{
HandleCustomException(exception);
}
}