永远可以返回异常

本文关键字:异常 返回 永远 | 更新日期: 2023-09-27 18:10:49

我有方法读取各种传感器和处理数据。在这些方法中,我有其他的方法,通过串行端口发送命令到电路(获得传感器值)。可能会发生通信错误,我想知道是否可以"返回"异常?例如:

public double AverageSensorValues()
{
  try
  {
   ...
   double sensor1Value = SensorValue(1);
   double sensor2Value = SensorValue(2);
   ...
   }
   catch (Exception ex)
   {
      MessageBox.Show("Error in AverageSensorValues()");
   }
}
public double SensorValue(int sensorNum)
{
   try {
   // Send command to circuit to return value.
   string response = SendCommand(commandStringToGetValue);
   // Check to see if response is an error
   bool isError = ErrorReturned(response);
   if(isError)
      ProcessError(response);  // Throws exception.
   ... // Other things that could cause exceptions to be thrown.
   }
   catch (Exception ex)
   {
      throw new Exception("Error in SensorValue()", ex);
   }
}
public void ProcessError(string errorResponse)
{
   // Split string and get error parameters (#, input command, etc.)
   throw new Exception(String.Format("Error-{0}: See ...", errorNumber));  // Is this OK? More readable than "ER,84,DM,3L" for example.
}

这是可以的还是被认为是"不好的做法"?

谢谢!

编辑

我看了各种各样的回应,看起来我做得完全错了。我试图用上面的例子作为一个快速的例子,但看起来我应该从一开始就发布完整的细节。下面是一个更详细的例子:

public double[] GetHeightAtCoords(CoordClass[] coords)  // Get height measurement at various positions. Called after button click, results are displayed on UI.
{
   try  // Error could occur within one of these methods. If it does, not Program critical but it should notify user and not return any result.
   {
   for(int coordIndex = 0; coordIndex < coords.Length; coordIndex++)  // Cycle through each desired position.
   {
      ...
      currentCoords = GetCurrentCoords();   // Get current actuator position.
      ... //Update UI.
      MoveToCoords(coords[coordIndex]);   // Move actuator to position.
      currentCoords = GetCurrentCoords(); // Verify position.
      EngageBrake();   // Lock actuator in place.
      double height = GetHeight(); // Read sensor data.
      ReleaseBrake();   // Release brake.
      ...
   }
  }
  catch (Exception ex)
  {
     // Display in statusbar.
     statusBar1.Text = String.Format("Error in GetHeightAtCoords(): {0}", ex.Message);
  }
   ...
   return heights;  // Return position heights array.
}
public CoordClass GetCurrentCoords()   // Method to read positional encoder values.
{
   ...
   try
   {
   double xPosition = GetXEncoderValue();   // Return x-coord value.
   double yPosition = GetYEncoderValue();   // Return y-coord value.
   }
   catch (Exception ex)
   {
      throw new Exception("Error in GetCurrentCoords(): {0}", ex.Message);
   }
   ...
   return new CoordClass(xPosition, yPosition); // Return current coords.
}
public void MoveToCoords(CoordClass coord)   // Method to move actuators to desired positions.
{
   try
   {
   ... 
   currentCoords = GetCurrentCoords(); // See where actuators are now.
   ... // Setup movement parameters.
   MoveToX(coord.X);   // Move x-axis actuator to position.
   MoveToY(coord.Y);   // Move y-axis actuator to position.
   }
   catch (Exception ex)
   {
      throw new Exception("Error in MoveToCoords(): {0}", ex.Message);
   }
   ...
}
public double GetXEncoderValue()   // Method to return x-coord value.
{
   string getXCoordCommand = "SR,ML,01,1";   // Serial command to get x-coord.
   ...
   string controllerResponse = SendReceive(getXCoordCommand);  // Send command, get response command.
   if(!ResponseOK(controllerResponse))   // If the response doesn't match the "command OK" response (i.e. SR,ML,01,1,OK)...
   {
      if(IsErrorResponse(controllerResponse))  // See if response is an error response (e.g. command error, status error, parameter count error, etc.)
         // Some known error type occurred, cannot continue. Format error string (e.g. ER,SRML,61) to something more meaningful and report to user (e.g. Read X Value Error: Status error.).
         throw new Exception("Read X Value Error-{0}: {1}", errorNumber, (ErrorEnum)errorNumber);
      else
         // Something else went wrong, cannot continue. Report generic error (Read X Value Error.).
         throw new Exception("Read X Value Error.");
   }
   ...
}
// GetYEncoderValue(), MoveToX(), MoveToY(), GetHeight(), EngageBrake() and ReleaseBrake() follow the same format as EngageBrake().

这是我的逻辑,如果…

调用顺序:getheightatcoordds () -> movetocoordds () -> getcurrentcoordds () -> GetXEncoderValue(),控制器响应错误。

在GetXEncoder()中抛出新的异常,在getcurrentcoordds()中捕获并重新抛出新的异常,在movetocoordds()中捕获并重新抛出新的异常,在getheightatcoordds()中捕获并在状态栏中显示消息(消息= "在getheightatcoordds()中出错:在movetocoordds()中出错:在getcurrentcoordds()中出错:读取X值错误-6:状态错误")。

因为GetXEncoder()可以在一个方法内的多个地方被调用,我认为如果我让原始异常一直冒出来,它对用户几乎没有帮助(例如:"Error in GetHeightAtCoords(): Read X Value Error-6: Status Error",具体是什么时间?以这个例子为例,哪个读取X值失败了?getheightatcoordds () -> movetocoordds () -> getcurrentcoordds () -> GetXEncoderValue()或getheightatcoordds () -> getcurrentcoordds () -> GetXEncoderValue() ?

希望这更清楚:/

这样的事情曾经发生过吗?你建议我怎么做呢?再次感谢大家的意见!

永远可以返回异常

总是抛出异常的方法有点难闻。看起来它处理了错误,然后继续。我宁愿这样做:

if(isError)
      throw MakeMeAnException(response);  
...
}
public Exception MakeMeAnException(string errorResponse)
{
   // Split string and get error parameters (#, input command, etc.)
   return new MyException(String.Format("Error-{0}: See ...", errorNumber)); 
}

很明显,if (isError)的结果总是抛出;在你的原始版本中,很难看出它做到了这一点。

而且,异常的堆栈跟踪被设置在抛出的位置,所以这会将堆栈跟踪设置在检测到错误的位置,而不是构造异常的位置,这看起来更好。

在你的代码中有更多的坏习惯。

  • 不要抛出new Exception;定义自己的异常类并抛出它。

  • 不要捕获每个异常,然后将其包装在一个新的异常中并抛出它。这到底是什么意思?如果每个方法都这样做呢?很快,你就会有一个被包裹了二十几层的异常,并且无法弄清楚异常的真正含义。

  • 不要捕获每个异常,然后显示一个消息框。首先,这是将错误处理机制代码与用户界面代码相结合;把这两者分开。其次,您可能会在这里报告各种异常——线程中止和内存不足等等。捕获特定的异常并处理它;如果你不知道如何恢复,就不要吃

使用这样的异常是没有意义的,异常应该出现在意外发生的时候。它们不应该是一般控制流程的一部分。

这很糟糕,因为您隐藏了异常的类型:

catch (Exception ex)
{
    throw new Exception("Error in SensorValue()", ex);
}

最好省略try { ... } catch { ... }。只捕捉那些你可以做一些有用的事情的异常。


这很糟糕,因为您捕获了所有内容,但没有显示实际错误是什么:

catch (Exception ex)
{
    MessageBox.Show("Error in AverageSensorValues()");
}

您可能捕获了OutOfMemoryException, NullReferenceException或其他完全的东西。你的用户不会知道的。至少显示异常消息。


throw new Exception(String.Format("Error-{0}: See ...", errorNumber));

这是异常的合理使用-将错误代码更改为异常。但是你可能应该使用一个比Exception更具体的类型——甚至可能是一个从Exception派生的自定义类

如果唯一的原因是硬件故障——是的,抛出一个异常说'硬件故障'是可以的。

如果用户有问题,你应该说"给我好的输入,再试一次"。

我的意思是,应该在导致程序不再运行或程序无法处理的情况下使用异常。

如果它是你可以恢复的东西,那么不。

但是,您应该捕获任何异常并适当地记录它们,以便您可以调试任何问题。

c#是否可以返回异常?

可以,但是只有几个理由抛出异常。例如,如果执行满足了一个不应该发生的条件。

看这里讨论了何时抛出异常。

因为它们是正常发生的事情。例外则不是控制流机制。用户经常会输入错误的密码,这不是意外特殊情况。例外应该是非常罕见的事情,UserHasDiedAtKeyboard类型的情况

回到你的代码。

显示异常的实际消息更有意义。

 catch (Exception ex)
   {
      MessageBox.Show(string.Format("Error in AverageSensorValues() - {0}", ex.Message));
   }

下面的代码看起来不对。返回自己的错误(或结果)对象,而不是抛出不必要的异常。

public void ProcessError(string errorResponse)
{
   // Split string and get error parameters (#, input command, etc.)
   throw new Exception(String.Format("Error-{0}: See ...", errorNumber));  // Is this OK? More readable than "ER,84,DM,3L" for example.
}