2009-11-26 170 views
2

我设计了一个简单的程序,它有一个计数器类,并且在计数器类内部我有增加计数,减少计数等的方法。然后,我向用户展示一个菜单,让他们进入他们的选择,例如。输入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--; 
    } 
+0

我的目标是确保当最终用户打开菜单时,如果选中的话会导致错误的菜单项被禁用或不可用。我认为这是一个变化“在关头”设计模式:) – BillW 2009-11-26 10:04:42

回答

7

对控制流使用异常不被认为是良好的做法。在你的情况下,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. 
    } 
} 
+1

一个很好的答案,但重要的一点是不应抛出ArgumentOutOfRangeException,我宁愿推荐InvalidOperationException或从中派生出来的东西。 – 2009-11-26 08:29:44

+0

@AdamRalph:同意 - InvalidOperationException是要抛出的正确的异常类型。编辑我的回答:) – 2009-11-26 08:31:26

+0

+1在良好的体系结构中的答案 – 2009-11-26 08:39:50

1

异常处理可以占用大量资源。如果你打算抛出异常以便捕获它并压制它,那就不要这样做。 而是做一些类似于从方法返回一个bool来指示调用者的成功。

public bool SubtractCount() { 
    if (count < 0) 
     return false; 
    count--; 
    return true; 
} 

来电者仍然可以处理这种情况有类似的逻辑,但没有例外

if (!myObjectOfCounterClass.SubtractCount()) 
    Console.writeLine("The count cannot be negative"); 

这是要点。

当你不想处理它们,或者你不能处理它们,或者你想让错误在你的直接编程环境之外传播时,抛出异常。使用异常处理等功能很有趣,但它们可能会过度使用 - 我常常犯有在.NET框架中使用有趣功能的情况。

+1

这不是一个非常明确的API设计。如果返回值为false会发生什么?它也违反命令/查询分离。 – 2009-11-26 08:22:53

+2

我认为,如果方法被命名为TrySubtractCount,那么它将是完全清楚的! – RCIX 2009-11-26 08:26:29

+0

至于正确的架构,我更喜欢@Mark Seemanns的答案 - http://stackoverflow.com/questions/1802228/c-how-to-handle-this-isituation/1802250#1802250 – 2009-11-26 08:39:10

0

事实上,似乎情况时数< 0不“例外”。使用正常的“如果”这个,没有必要例外。

1

当您只使用流量控制时,不应该使用流量控制异常。您可以检查小于零,并且(a)不对其采取行动或(b)显示消息或(c)将事情关在正确的位置。

除了例外,你基本上将所有东西放在地板上,就好像发生了一场巨大的灾难,当它可以更优雅地处理时,甚至发出警告并继续。

1

我认为在SubtractCount()方法中抛出一个异常,如果该值已经为零,那也没关系。

btw应该if (count < 0)不是if (count == 0)

但是,我会让用户界面阻止用户选择减计数,如果它已经是零,从而避免了第一个例外情况。

顺便说一句 - 不要引发ArgumentOutOfRangeException。这应该在传递给方法的参数不在可接受的范围内时使用。你的方法不接受任何参数。更合适的异常类型是InvalidOperationException。

+0

不,计数不能是负数,但可以为零。 – Alex 2009-11-26 08:25:24

+0

我明白这一点。这意味着您需要测试调用SubtractCount()的情况,并且计数已经为零,即如果(count == 0)抛出异常 – 2009-11-26 08:28:33

0

那么,首先你应该确保柜台实际上不会是负面的。目前它会递减到-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并让异常像其他意外错误一样处理。

0

例外应该只在特殊情况下使用,用户再次点击减少按钮并不例外,您可以通过简单的控制逻辑处理它。你可以不减少计数器,如果它达到零,此外你应该改变你的UI它应该阻止用户减少选项,如果计数器达到零,所以用户永远不会有进一步减少它的选项。

相关问题