¿Cómo usar la palabra clave throws al estilo Java en C #?

91

En Java, la throwspalabra clave permite que un método declare que no manejará una excepción por sí solo, sino que la lanzará al método de llamada.

¿Existe una palabra clave / atributo similar en C #?

Si no hay equivalente, ¿cómo puede lograr el mismo efecto (o uno similar)?

Louis Rhys
fuente

Respuestas:

78

En Java, debe manejar una excepción o marcar el método como uno que pueda lanzarlo usando la throwspalabra clave.

C # no tiene esta palabra clave o una equivalente, como en C #, si no maneja una excepción, se disparará, hasta que se detecte o, si no se detecta, finalizará el programa.

Si desea manejarlo, vuelva a lanzarlo, puede hacer lo siguiente:

try
{
  // code that throws an exception
}
catch(ArgumentNullException ex)
{
  // code that handles the exception
  throw;
}
Oded
fuente
1
"burbujeará", ¿significa esto que esto es equivalente a que todos los métodos tengan una cláusula throws en Java?
Louis Rhys
1
@Louis RH - algo así. Significa que una excepción, si no se maneja, subirá en la cadena de llamadas a través de cada función de llamada hasta que se maneje.
Oded el
1
@Louis RH no completamente, eso significaría que tendría que detectar la Excepción al menos en su Main para compilar el código. Debido a que C # no conoce las excepciones marcadas, depende de usted detectarlas, de lo contrario, simplemente aterrizarán en el tiempo de ejecución e interrumpirán su código.
Johannes Wachter
1
@jwatcher: un método principal también puede tener una cláusula de lanzamiento.
Louis Rhys
4
@AshishKamble - eh. Cuestión de opinión. El manejo de excepciones es diferente en .NET. No asuma que sabe lo que es "mejor".
Oded el
109

El operador pregunta sobre el equivalente en C # de la throwscláusula de Java, no la throwpalabra clave. Esto se usa en firmas de métodos en Java para indicar que se puede lanzar una excepción marcada.

En C #, no existe un equivalente directo de una excepción marcada de Java. C # no tiene una cláusula de firma de método equivalente.

// Java - need to have throws clause if IOException not handled
public void readFile() throws java.io.IOException {
  ...not explicitly handling java.io.IOException...
}

se traduce en

// C# - no equivalent of throws clause exceptions are unchecked
public void ReadFile() 
{
  ...not explicitly handling System.IO.IOException...
}
serg10
fuente
30

Sí, este es un hilo antiguo, sin embargo, con frecuencia encuentro hilos antiguos cuando busco respuestas en Google, así que pensé que agregaría algo útil que he encontrado.

Si está utilizando Visual Studio 2012, hay una herramienta incorporada que se puede utilizar para permitir un equivalente de "lanzamientos" de nivel IDE.

Si usa Comentarios de documentación XML , como se mencionó anteriormente, puede usar la etiqueta <exception> para especificar el tipo de excepción lanzada por el método o clase, así como información sobre cuándo o por qué se lanza.

ejemplo:

    /// <summary>This method throws an exception.</summary>
    /// <param name="myPath">A path to a directory that will be zipped.</param>
    /// <exception cref="IOException">This exception is thrown if the archive already exists</exception>
    public void FooThrowsAnException (string myPath)
    {
        // This will throw an IO exception
        ZipFile.CreateFromDirectory(myPath);
    }
mvanella
fuente
4
OP, esta es tu respuesta. Supongo, pero es throwsprobable que JAVA no signifique nada para el tiempo de ejecución, además de ser informativo para el desarrollador. Asimismo, lo que @mvanella señaló aquí es la forma en que C # hace exactamente lo mismo. Supongo que ya sabe que esta "documentación xml" tiene un propósito más importante. Sé que este hilo es antiguo.
Hari Lubovac
En realidad, Java no genera excepciones a menos que se especifique explícitamente en una throwscláusula o se genere mediante un throwcomando. Eso significa que si ocurre una RunTimeException y no se maneja en el mismo método donde ocurre, la ejecución se detendrá allí.
Pedro Lima
18

Aquí hay una respuesta a una pregunta similar que acabo de encontrar en bytes.com :

La respuesta corta es no. No hay excepciones marcadas en C #. El diseñador del lenguaje analiza esta decisión en esta entrevista:

http://www.artima.com/intv/handcuffs.html

Lo más cercano que puede conseguir es usar las etiquetas en su documentación XML y distribuir documentos generados por NDoc con su código / ensamblados para que otras personas puedan ver qué excepciones arroja (que es exactamente lo que hace MS en la documentación de MSDN). Sin embargo, no puede confiar en que el compilador le informe sobre las excepciones no controladas, como puede que esté acostumbrado en Java.

Andreas Dolk
fuente
7

Después de leer la mayoría de las respuestas aquí, me gustaría agregar un par de pensamientos.

  1. Confiar en los comentarios de documentación XML y esperar que otros confíen en ellos es una mala elección. La mayoría del código C # con el que me he encontrado no documenta los métodos de forma completa y coherente con los comentarios de documentación XML. Y luego está el problema más grande de que sin las excepciones marcadas en C #, ¿cómo podría documentar todas las excepciones que arroja su método con el propósito de que su usuario de API sepa cómo manejarlas todas individualmente? Recuerde, solo conoce los que lanza usted mismo con la palabra clave throw en su implementación. Las API que está utilizando dentro de la implementación de su método también pueden generar excepciones que no conoce porque es posible que no estén documentadas y no las esté manejando en su implementación, por lo que explotarán frente a la persona que llama de su método. En otras palabras,

  2. Andreas vinculó una entrevista con Anders Hejlsberg en las respuestas aquí sobre por qué el equipo de diseño de C # decidió no ver las excepciones. La respuesta definitiva a la pregunta original está oculta en esa entrevista:

Los programadores protegen su código escribiendo try.

En otras palabras, nadie debería estar interesado en qué tipo de excepción se puede esperar para una API en particular, ya que siempre las encontrará todas en todas partes. Y si realmente quiere preocuparse por las excepciones particulares, cómo manejarlas depende de usted y no de alguien que defina una firma de método con algo como la palabra clave Java throws, lo que obliga a un usuario de API a manejar excepciones particulares.

-

Personalmente, estoy desgarrado aquí. Estoy de acuerdo con Anders en que haber verificado las excepciones no resuelve el problema sin agregar problemas nuevos y diferentes. Al igual que con los comentarios de la documentación XML, rara vez veo código C # con todo envuelto en bloques de prueba finalmente. Me parece que esta es de hecho su única opción y algo que parece una buena práctica.

Tobias
fuente
3

En realidad, no haber comprobado las excepciones en C # puede considerarse algo bueno o malo.

Yo mismo considero que es una buena solución ya que las excepciones marcadas le brindan los siguientes problemas:

  1. Excepciones técnicas que se filtran a la capa de dominio / negocio porque no puede manejarlas adecuadamente en el nivel bajo.
  2. Pertenecen a la firma del método, que no siempre funciona bien con el diseño de API.

Por eso, en la mayoría de las aplicaciones más grandes, verá el siguiente patrón a menudo cuando se activen las Excepciones:

try {
    // Some Code
} catch(SomeException ex){
    throw new RuntimeException(ex);
}

Lo que esencialmente significa emular la forma en que C # / .NET maneja todas las excepciones.

Johannes Wachter
fuente
¡No puedo imaginar cómo se mezclarían las excepciones marcadas con las lambdas!
Gabe
@Gabe: Estoy seguro de que se le podría ocurrir algún concepto que le permita mezclarlos, pero como dije, las excepciones marcadas en Java tampoco son una buena práctica, especialmente en aplicaciones más complejas. Entonces es bueno que no estén en C #.
Johannes Wachter
3

Estás preguntando sobre esto:

Relanzar una excepción

public void Method()
{
  try
  {
      int x = 0;
      int sum = 100/x;
  }
  catch(DivideByZeroException e)
  {
      throw;
  }
}

o

static void Main() 
    {
        string s = null;

        if (s == null) 
        {
            throw new ArgumentNullException();
        }

        Console.Write("The string s is null"); // not executed
    }
Pranay Rana
fuente
3
+1 para usar throw. Al usarlo, el seguimiento de la pila no se perderá.
Giuseppe Accaputo
2

Existen algunas similitudes fugaces entre .Net CodeContract EnsuresOnThrow<>y el throwsdescriptor de java , en el sentido de que ambos pueden señalar a la persona que llama como el tipo de excepción que podría surgir de una función o método, aunque también hay grandes diferencias entre los 2:

  • EnsuresOnThrow<>va más allá de simplemente indicar qué excepciones se pueden lanzar, sino que también estipula las condiciones bajo las cuales se garantiza que se lanzarán; esto puede ser un código bastante oneroso en el método llamado si la condición de excepción no es trivial de identificar. Java throwsproporciona una indicación de qué excepciones podrían lanzarse (es decir, en mi opinión, el enfoque en .Net está dentro del método que se contrae para probar el throw, mientras que en Java el enfoque se desplaza hacia el llamador para reconocer la posibilidad de la excepción).
  • .Net CC no hace la distinción entre las excepciones marcadas y no marcadas que tiene Java, aunque la sección 2.2.2 del manual CC sí menciona

"use condiciones posteriores excepcionales solo para aquellas excepciones que una persona que llama debería esperar como parte de la API"

  • En .Net, la persona que llama puede determinar si debe o no hacer algo con la excepción (por ejemplo, desactivando contratos). En Java, la persona que llama debe hacer algo , incluso si agrega una throwspara la misma excepción en su interfaz.

Codifique el manual de contratos aquí

StuartLC
fuente
0

Si el propósito del método c # es solo lanzar una excepción (como dice el tipo de retorno js), recomendaría simplemente devolver esa excepción. Vea el ejemplo a continuación:

    public EntityNotFoundException GetEntityNotFoundException(Type entityType, object id)
    {
        return new EntityNotFoundException($"The object '{entityType.Name}' with given id '{id}' not found.");
    }

    public TEntity GetEntity<TEntity>(string id)
    {
        var entity = session.Get<TEntity>(id);
        if (entity == null)
            throw GetEntityNotFoundException(typeof(TEntity), id);
        return entity;
    }

ADMITIR
fuente
-1

Para aquellos que se preguntan, ni siquiera necesitan definir lo que capturan para pasarlo al siguiente método. En caso de que desee todo el manejo de errores en un hilo principal, puede simplemente capturar todo y pasarlo así:

try {
    //your code here
}
catch {
    //this will throw any exceptions caught by this try/catch
    throw;
}
Simon Jensen
fuente
Por favor, edite la respuesta. Accidentalmente hice clic en -1. No puedo eliminarlo hasta que hagas algún cambio.
proximab