在这种情况下我应该使用例外吗?
我设计了一个简单的程序,它有一个计数器类,并且在计数器类内部我有增加计数,减少计数等的方法。然后,我向用户展示一个菜单,让他们进入他们的选择,例如。输入1作为选项1,等等。我不希望计数是负数,所以为了处理这个问题,我使用计数器类的SubtractCount方法抛出ArguemetOutOfRangeException,当计数< 0.在这种情况下我应该使用例外吗?
然后我有如果它发生,我的switch语句会捕获该异常。我的问题是:使用例外来确保计数永远不会是负数是不是很糟糕?我应该以不同的方式做吗?或者更好的是,有没有更好的方法来实现这一目标?
代码片段:
static void Driver()
{
switch (userChoice)
{
case 1: // if user picks a 1, the count is deincremented
try {
myObjectOfCounterClass.SubtractCount();
}
catch (ArguemetOutOfRangeException ex)
{
console.writeLine(ex.message);
}
break;
// case 2, case 3 etc.
}
class Counter
{
private int count;
public void SubtractCount()
{
if (count < 0)
throw new ArguementOutOfRangeException("The count can never be negative!");
else
count--;
}
对控制流使用异常不被认为是良好的做法。在你的情况下,Tester-Doer模式会更合适。
你可以在你的柜台类更改为这样的事情:
class Counter
{
private int count;
public bool CanSubtractCount
{
get { return this.count >= 0; }
}
public void SubtractCount()
{
if (!this.CanSubtractCount)
throw new InvalidOperationException("The count can never be negative!");
else
this.count--;
}
您现在可以改写你的客户是这样的:
static void Driver()
{
switch (userChoice)
{
case 1: // if user picks a 1, the count is deincremented
if(myObjectOfCounterClass.CanSubtractCount)
{
myObjectOfCounterClass.SubtractCount();
}
else
{
// Write a message to the user?
}
break;
// case 2, case 3 etc.
}
}
一个很好的答案,但重要的一点是不应抛出ArgumentOutOfRangeException,我宁愿推荐InvalidOperationException或从中派生出来的东西。 – 2009-11-26 08:29:44
@AdamRalph:同意 - InvalidOperationException是要抛出的正确的异常类型。编辑我的回答:) – 2009-11-26 08:31:26
+1在良好的体系结构中的答案 – 2009-11-26 08:39:50
异常处理可以占用大量资源。如果你打算抛出异常以便捕获它并压制它,那就不要这样做。 而是做一些类似于从方法返回一个bool来指示调用者的成功。
public bool SubtractCount() {
if (count < 0)
return false;
count--;
return true;
}
来电者仍然可以处理这种情况有类似的逻辑,但没有例外
if (!myObjectOfCounterClass.SubtractCount())
Console.writeLine("The count cannot be negative");
这是要点。
当你不想处理它们,或者你不能处理它们,或者你想让错误在你的直接编程环境之外传播时,抛出异常。使用异常处理等功能很有趣,但它们可能会过度使用 - 我常常犯有在.NET框架中使用有趣功能的情况。
这不是一个非常明确的API设计。如果返回值为false会发生什么?它也违反命令/查询分离。 – 2009-11-26 08:22:53
我认为,如果方法被命名为TrySubtractCount,那么它将是完全清楚的! – RCIX 2009-11-26 08:26:29
至于正确的架构,我更喜欢@Mark Seemanns的答案 - http://stackoverflow.com/questions/1802228/c-how-to-handle-this-isituation/1802250#1802250 – 2009-11-26 08:39:10
事实上,似乎情况时数< 0不“例外”。使用正常的“如果”这个,没有必要例外。
当您只使用流量控制时,不应该使用流量控制异常。您可以检查小于零,并且(a)不对其采取行动或(b)显示消息或(c)将事情关在正确的位置。
除了例外,你基本上将所有东西放在地板上,就好像发生了一场巨大的灾难,当它可以更优雅地处理时,甚至发出警告并继续。
我认为在SubtractCount()方法中抛出一个异常,如果该值已经为零,那也没关系。
btw应该if (count < 0)
不是if (count == 0)
?
但是,我会让用户界面阻止用户选择减计数,如果它已经是零,从而避免了第一个例外情况。
顺便说一句 - 不要引发ArgumentOutOfRangeException。这应该在传递给方法的参数不在可接受的范围内时使用。你的方法不接受任何参数。更合适的异常类型是InvalidOperationException。
不,计数不能是负数,但可以为零。 – Alex 2009-11-26 08:25:24
我明白这一点。这意味着您需要测试调用SubtractCount()的情况,并且计数已经为零,即如果(count == 0)抛出异常 – 2009-11-26 08:28:33
那么,首先你应该确保柜台实际上不会是负面的。目前它会递减到-1并抛出异常,如果你试图将它递减到-2。
作为替代,只是捕捉异常,可以公开检查为CanDecrement
属性,以便它可以单独使用:
class Counter {
private int count;
public bool CanDecrement { get{ return count > 0; } }
public void Decrement() {
if (!CanDecrement) {
throw new ArguementOutOfRangeException("The count can never be negative!");
}
count--;
}
}
用法:
if (myObjectOfCounterClass.CanDecrement) {
myObjectOfCounterClass.Decrement();
} else {
Console.WriteLine("The count can not be negative.");
}
这种方式可以将该属性用于您希望发生该情况的代码,并且在代码中通常不会发生的情况下,您可以拨打Decrement
并让异常像其他意外错误一样处理。
例外应该只在特殊情况下使用,用户再次点击减少按钮并不例外,您可以通过简单的控制逻辑处理它。你可以不减少计数器,如果它达到零,此外你应该改变你的UI它应该阻止用户减少选项,如果计数器达到零,所以用户永远不会有进一步减少它的选项。
我的目标是确保当最终用户打开菜单时,如果选中的话会导致错误的菜单项被禁用或不可用。我认为这是一个变化“在关头”设计模式:) – BillW 2009-11-26 10:04:42