我知道两种异常处理方法,让我们来看看它们。

  1. 合同方式。

    如果方法没有按照它在方法头中所做的那样做,它将抛出异常。 因此,该方法“承诺”它将执行操作,如果由于某种原因失败,它将抛出异常。

  2. 特殊的方法。

    只有在发生真正奇怪的事情时抛出异常。 当您可以使用正常控制流(If语句)解决情况时,不应使用异常。 您不会像在合同方法中那样使用Exceptions作为控制流。

让我们在不同的情况下使用这两种方法:

我们有一个Customer类,它有一个名为OrderProduct的方法。

合同方式:

class Customer
{
     public void OrderProduct(Product product)
     {
           if((m_credit - product.Price) < 0)
                  throw new NoCreditException("Not enough credit!");
           // do stuff 
     }
}

特殊方法:

class Customer
{
     public bool OrderProduct(Product product)
     {
          if((m_credit - product.Price) < 0)
                   return false;
          // do stuff
          return true;
     }
}

if !(customer.OrderProduct(product))
            Console.WriteLine("Not enough credit!");
else
   // go on with your life

在这里,我更喜欢这种特殊的方法,因为假设他没有赢得彩票,客户没有钱也不是真正的例外。

但这是一种我在合同风格上犯错的情况。

卓越:

class CarController
{
     // returns null if car creation failed.
     public Car CreateCar(string model)
     {
         // something went wrong, wrong model
         return null;
     }
 }

当我调用一个名为CreateCar的方法时,我该死的期待一个Car实例而不是一些糟糕的空指针,这可能会破坏我的运行代码十几行。 因此,我更喜欢与此合同:

class CarController
{

     public Car CreateCar(string model)
     {
         // something went wrong, wrong model
         throw new CarModelNotKnownException("Model unkown");

         return new Car();
     }
 }

你用哪种风格? 您认为对例外的最佳一般方法是什么?

===============>>#1 票数:6 已采纳

我赞成你称之为“合同”的方法。 在支持异常的语言中,不需要返回空值或其他特殊值来指示错误。 我发现当代码没有一堆“if(result == NULL)”或“if(result == -1)”子句与可能非常简单,直接的逻辑混合时,会更容易理解代码。

===============>>#2 票数:1

我通常的方法是使用契约来处理由于“客户端”调用而导致的任何类型的错误,即由于外部错误(即ArgumentNullException)。

不处理参数上的每个错误。 提出了一个例外,“客户”负责处理它。 另一方面,对于内部错误总是尝试纠正它们(就好像由于某种原因无法获得数据库连接),并且只有在您无法处理它时才会重新启动异常。

重要的是要记住,在这样的级别上大多数未处理的异常无论如何都无法由客户端处理,因此他们可能会进入最常见的异常处理程序,因此如果发生这种异常,您可能仍然是FUBAR。

===============>>#3 票数:0

我相信如果您正在构建一个将由外部程序使用的类(或将被其他程序重用),那么您应该使用合同方法。 一个很好的例子是任何类型的API。

===============>>#4 票数:0

如果您确实对异常感兴趣并想考虑如何使用它们来构建健壮的系统,请考虑阅读在存在软件错误的情况下制作可靠的分布式系统

===============>>#5 票数:0

两种方法都是对的。 这意味着合同应该以这样的方式编写,以便为所有不是真正例外的案件指定不需要抛出异常的行为。

请注意,根据代码调用者的期望,某些情况可能会或可能不会例外。 如果调用者期望字典将包含某个项目,并且该项目的缺失将指示严重问题,则未能找到该项目是异常情况并且应该导致抛出异常。 但是,如果呼叫者并不真正知道某个项目是否存在,并且同样准备好处理其存在或缺席,那么该项目的缺失将是预期的条件,不应导致异常。 处理调用者期望中的这种变化的最佳方法是让合同指定两种方法:DoSomething方法和TryDoSomething方法,例如

TValue GetValue(TKey Key);
bool TryGetValue(TKey Key, ref TValue value);

请注意,虽然标准的'try'模式如上所示,但如果设计一个生成项目的接口,一些替代方案也可能会有所帮助:

// In case of failure, set ok false and return default<TValue>.
TValue TryGetResult(ref bool ok, TParam param);
// In case of failure, indicate particular problem in GetKeyErrorInfo
// and return default<TValue>.
TValue TryGetResult(ref GetKeyErrorInfo errorInfo, ref TParam param);

请注意,在接口中使用类似普通TryGetResult模式的东西会使接口对结果类型不变; 使用上述模式之一将允许接口相对于结果类型是协变的。 此外,它将允许结果用于'var'声明:

var myThingResult = myThing.TryGetSomeValue(ref ok, whatever);
  if (ok) { do_whatever }

不完全是标准方法,但在某些情况下,优势可能是合理的。

  ask by translate from so

未解决问题?本站智能推荐: