Всегда ли можно вернуть исключение? - PullRequest
2 голосов
/ 11 октября 2011

У меня есть методы для чтения различных датчиков и обработки данных. В рамках этих методов у меня есть другие методы, которые отправляют команды в цепь через последовательный порт (чтобы получить значения датчика). Может произойти ошибка связи, и мне было интересно, можно ли когда-нибудь "вернуть" исключение? Например:

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.
}

Это когда-нибудь нормально или считается "плохой практикой"?

Спасибо!

EDIT

Хорошо, я перечитал различные ответы, и похоже, что я делаю это совершенно неправильно (голый со мной, я - мех. Англ.). Я попытался использовать вышеизложенное в качестве быстрого примера, но похоже, что я должен был просто опубликовать полную информацию с самого начала. Итак, вот более подробный пример моей ситуации:

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().

Вот моя логика, если ...

Порядок вызовов: GetHeightAtCoords () -> MoveToCoords () -> GetCurrentCoords () -> GetXEncoderValue (), ошибка с ответом контроллера.

Создать новое исключение в GetXEncoder (), перехватить в GetCurrentCoords () и повторно выдать новое исключение, перехватить в MoveToCoords () и повторно выбросить новое исключение, поймать в GetHeightAtCoords () и отобразить сообщение в строке состояния (message = " Ошибка в GetHeightAtCoords (): Ошибка в MoveToCoords (): Ошибка в GetCurrentCoords (): Чтение значения X Ошибка-6: Ошибка состояния ").

Поскольку GetXEncoder () может вызываться из нескольких мест внутри метода, я решил, что если я позволю исходному исключению всплыть до конца, это будет мало чем помочь пользователю (например, «Ошибка в GetHeightAtCoords (): чтение» Ошибка значения X-6: ошибка состояния ", в какое время?). Возьмите этот пример, какое значение Read X Value не удалось? GetHeightAtCoords () -> MoveToCoords () -> GetCurrentCoords () -> GetXEncoderValue () ИЛИ GetHeightAtCoords () -> GetCurrentCoords () -> GetXEncoderValue ()?

Надеюсь, это более понятно: /

Что-нибудь подобное когда-нибудь было сделано? Как бы вы посоветовали мне продолжить? Еще раз спасибо всем за ваш вклад!

Ответы [ 6 ]

11 голосов
/ 11 октября 2011

Создание метода, который всегда выбрасывает исключение, немного пахнет.Похоже, что обрабатывает ошибку, а затем продолжает.Я бы предпочел сделать это так:

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;определить свой собственный класс исключений и бросить его.Таким образом, вызывающий абонент может специально перехватить ваше исключение.

  • Не перехватывайте каждое исключение, а затем заключите его в новое исключение и выбросьте его.Какого черта в этом смысл?Что если каждый метод сделал это?Вскоре у вас будет исключение, обернутое на два десятка уровней, и вы не сможете понять, что на самом деле означает это исключение.

  • Не перехватывайте каждое исключение и затем отображайте окно сообщения.Во-первых, это объединение кода механизма обработки ошибок с кодом пользовательского интерфейса;держите эти два отдельно.Во-вторых, вы можете сообщать здесь обо всех видах исключений - прерывания потоков, нехватка памяти и все такое.Поймать специфическое исключение и обработать его; если вы не знаете, как излечиться от него, не ешьте его.

1 голос
/ 11 октября 2011

Нет смысла использовать подобное исключение, исключения должны быть, когда происходит что-то неожиданное. Они НЕ должны быть частью общего потока управления.

1 голос
/ 11 октября 2011

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.
}
1 голос
/ 11 октября 2011

Это плохо, потому что вы скрываете тип исключения:

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.

0 голосов
/ 11 октября 2011

ИМХО, исключения следует использовать в обстоятельствах, которые приводят к тому, что ваша программа перестает функционировать или которую программа не может обработать.

Если это что-то, из чего вы можете восстановиться, то нет.

однако вы должны перехватывать любые исключения и регистрировать их соответствующим образом, чтобы вы могли отладить любые проблемы.

0 голосов
/ 11 октября 2011

Если единственной причиной является неисправность оборудования - да, можно вызывать исключение, говорящее о неисправности оборудования.

Если пользователи ошибаются, вам лучше сказать «дайте мне хороший ввод, попробуйте еще раз».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...