Cuándo crear una excepción personalizada en C #

9

Estoy escribiendo una clase para interactuar con un dispositivo de hardware simple a través de un puerto COM. El dispositivo se puede configurar para usar varios modos, por lo que mi clase tiene una SetOperatingModefunción, que toma una enumde tipo UsbDeviceMode. Se ve algo como esto:

class UsbDevice
{
    public void SetOperatingMode(UsbDeviceMode mode)
    { 
     byte[] buffer = new byte[4];
     buffer[0] = 0x5A;
     buffer[1] = 0x02;
     buffer[2] = (byte)mode;
     buffer[3] = 0x00; //IO_TYPE is always 0 in this case.

     _port.Write(buffer, 0, 4);
     int read = _port.Read(buffer, 0, 2);
     bool successfulSet = (read == 2 && buffer[0] == 0xFF && buffer[1] == 0x00);
    }
}

enum UsbDeviceMode
{
  IO_MODE = 0x00,
  IO_CHANGE = 0x10,
  I2C_S_20KHZ = 0x20,
  I2C_S_50KHZ = 0x30,
  I2C_S_100KHZ = 0x40,
  I2C_S_400KHZ = 0x50,
  I2C_H_100KHZ = 0x60,
  I2C_H_400KHZ = 0x70,
  I2C_H_1000KHZ = 0x80,
  SPI_MODE = 0x90,
  SERIAL = 0x01
};

Existe la clara posibilidad de que esta operación pueda fallar debido a varias razones: el puerto COM ya no existe, el dispositivo puede haberse bloqueado o fallado, o por alguna razón, la operación falló.

Un fracaso sería inesperado, pero no infrecuente. Hay dos modos distintos de fallas: el puerto COM genera una excepción ( TimeoutExceptiony InvalidOperationExceptiones la esperada). O podría leer un indicador de falla del dispositivo.

En cualquier caso, si SetOperatingMode()falla, entonces el dispositivo o la comunicación se interrumpe de alguna manera, y esta clase no puede hacer nada al respecto.

Tengo 2 preguntas:

  1. ¿Debo "pre-tirar" el InvalidOperationExceptionsi el puerto está cerrado? De la documentación de MSDN, SerialPort.Writey SerialPortleer lanzará si el puerto está cerrado. Puedo verificar eso en la parte superior de la función, o simplemente puedo dejarlo _port.Write()tirar.
  2. ¿Debería haber un tipo de excepción completamente nuevo cuando successfulSetes false? Si successfulSetes así false, no hay nada que esta clase pueda hacer. ¿Debería haber algún tipo de SetOperatingModeFailedExceptionexcepción para distinguir entre la falla del puerto COM o la falla del dispositivo? Parece bastante lento crear una clase de excepción completa solo para este lugar.
CurtisHx
fuente

Respuestas:

10

Use una excepción personalizada cuando desee que los usuarios puedan distinguir mediante programación entre ciertas condiciones de error. Si esa situación no existe, puede lanzar una excepción más "general" y evitar crear la clase de excepción personalizada.

En el caso específico de su SetOperatingMode()ejemplo, a menos que necesite indicar formas específicas en que esta llamada al método podría fallar, es mejor que use una excepción más general. En otras palabras, si es su intención lanzar una SetOperatingModeFailedExceptionexcepción como posible resultado de una llamada SetOperatingMode(), pero no distinguir programáticamente qué tipo de falla de modo operativo ocurrió, entonces puede prescindir de crear una excepción personalizada (ya que es la única que podría ser lanzado), y simplemente lanzar un InvalidOperationException, que es probablemente la excepción existente más cercana.

Si aún desea crear una excepción personalizada, cree una que sea reutilizable a través de diferentes métodos, como OperationFailedException.

Robert Harvey
fuente
2

Crear una clase es fácil. No es un proceso lento en absoluto. La depuración de código que oculta los problemas es difícil. Y consume mucho tiempo.

Cuando decida crear una excepción o no, la pregunta que debe hacerse es "¿es este comportamiento normal, el comportamiento esperado o es excepcional?".

En este caso, el comportamiento esperado es que el modo operativo siempre está configurado. Por lo tanto, sugeriría que se deban lanzar excepciones. Permitiría cualquier excepción de la operación de escritura. También crearía una SetOperatingModeFailedException si la última línea revela que se ha producido un error.

En este caso, su método solo tiene la responsabilidad de intentar establecer el modo operativo. No tiene la responsabilidad de administrar la conexión. Esa es la responsabilidad de otra persona y si no se ha hecho correctamente, se debe lanzar una excepción.

Stephen
fuente
Parece que has entendido mal lo que está pidiendo. ¿Debería usar uno de los tipos de excepción existentes o rodar el suyo?
Robert Harvey
1
En realidad respondí sus preguntas. "Permitiría que surgieran excepciones de la operación de escritura". (es decir, no se moleste en comprobar si el puerto está abierto) y "cree una excepción SetOperatingModeFailedException".
Stephen
1
No. No es necesaria una excepción personalizada. ¿Qué otra excepción podría arrojar el método, excepto la que elija? ¿Cómo agrega SetOperatingModeFailedException algún valor más allá de, por ejemplo, InvalidOperationException? Ninguna de las excepciones le dice por qué ocurrió la falla, o le brinda una forma de responder programáticamente en función del tipo de excepción que se produjo. Y crear nuevas clases de Excepción no es gratuito .
Robert Harvey
1
¿Qué valor agrega? Agrega mucho valor cuando se documenta adecuadamente. Dice que este problema específico sucedió. No está claro que el código de llamada no pueda recuperarse de este error.
Stephen
Puede proporcionar un mensaje de error detallado en cualquier excepción que arroje. A menos que planee usar excepciones específicas para proporcionar control programático a la persona que llama, creo que crear una excepción personalizada es una pérdida de tiempo. No tome mi palabra, lea esto , que dice "Cree sus propias excepciones definidas por el usuario si desea que los usuarios puedan distinguir programáticamente entre algunas condiciones de error".
Robert Harvey