tipos qué programacion metodos metodo llamar funciones evento ejercicios consola c# .net exception exception-handling checked-exceptions

c# - qué - tipos de metodos en programacion



declarar un método siempre arroja una excepción? (11)

Tengo un método como ...

int f() { try { int i = process(); return i; } catch(Exception ex) { ThrowSpecificFault(ex); } }

Esto produce un error de compilación, "no todas las rutas de código devuelven un valor". Pero en mi caso, ThrowSpecificFault () siempre lanzará la excepción (la apropiada). Así que me veo forzado a poner un valor de retorno al final, pero esto es feo.

El propósito de este patrón en primer lugar es porque "process ()" es una llamada a un servicio web externo pero necesita traducir una variedad de diferentes excepciones para que coincidan con la interfaz esperada de un cliente (~ patrón de fachada, supongo).

¿Alguna forma más limpia de hacer esto?


El problema aquí es que si ingresa al bloque catch en f() su función nunca devolverá un valor. Esto dará como resultado un error porque declaró su función como int que significa que le dijo al compilador que su método devolverá un entero.

El siguiente código hará lo que está buscando y siempre devolverá un entero.

int f() { int i = 0; try { i = process(); } catch(Exception ex) { ThrowSpecificFault(ex); } return i; }

ponga la declaración de devolución al final de su función y estará bien.

Siempre es una buena idea asegurarse de que su método siempre devolverá un valor, independientemente de la ruta de ejecución por la que pase su aplicación.


En este momento, un tipo de devolución puede ser un tipo, o "vacío", que significa "sin tipo de devolución". En teoría, podríamos agregar un segundo tipo de retorno especial "nunca", que tiene la semántica que desea. El punto final de una declaración de expresión que consiste en una llamada a un método "nunca" de retorno se consideraría inalcanzable, por lo que sería legal en todos los contextos en C # en los que un "goto", "throw" o "return" es legal .

Es altamente improbable que esto se agregue al sistema de tipos ahora, diez años después. La próxima vez que diseñe un sistema de tipos desde cero, recuerde incluir un tipo "nunca".


En tu caso pero ese es tu conocimiento no el compilador. Ahora hay una manera de decir que este método seguramente producirá una excepción desagradable.

Prueba esto

int f() { try { return process(); } catch(Exception ex) { ThrowSpecificFault(ex); } return -1; }

También puedes usar la palabra clave lanzar

int f() { try { return process(); } catch(Exception ex) { throw ThrowSpecificFault(ex); } }

Pero entonces ese método debería devolver alguna excepción en lugar de tirarlo.


Le sugiero que convierta ThrowSpecificFault(ex) para throw SpecificFault(ex) ; el método SpecificFault devolvería el objeto de excepción que se lanzará en lugar de lanzarlo por sí mismo. Mucho más limpio.

Este es el patrón recomendado por las directrices de Microsoft (busque el texto "Usar métodos del generador de excepciones").


No.

Imagínese si ThrowSpecificFault estuviera definido en una DLL separada. Si modifica la DLL para no lanzar una excepción y luego ejecuta su programa sin volver a compilarlo, ¿qué pasaría?


Puedes hacer así:

catch (Exception ex) { Exception e = CreateSpecificFault(ex); throw e; }


Qué tal si:

int f() { int i = -1; try { i = process(); } catch(Exception ex) { ThrowSpecificFault(ex); } return i; }


Sí.

No espere que ThrowSpecificFault () lance la excepción. Haga que devuelva la excepción, luego tírela aquí.

En realidad, también tiene más sentido. No se usan excepciones para el flujo ''normal'', por lo que si lanza una excepción cada vez, la excepción se convierte en la regla. Cree la excepción específica en la función y tírela aquí porque es una excepción al flujo aquí.


Supongo que podrías hacer que ThrowSpecificFault devuelva un Objeto, y luego podrías

return ThrowSpecificFault(ex)

De lo contrario, podría volver a escribir ThrowSpecificFault como un constructor para un subtipo de excepción, o simplemente podría convertir ThrowSpecificFault en una fábrica que cree la excepción pero no la lance.


Tienes tres opciones:

Siempre devuelvo i pero pre-declara:

int f() { int i = 0; // or some other meaningful default try { i = process(); } catch(Exception ex) { ThrowSpecificFault(ex); } return i; }

Devuelva la excepción del método y lance eso:

int f() { try { int i = process(); return i; } catch(Exception ex) { throw GenerateSpecificFaultException(ex); } }

O crea una clase de excepción personalizada y lanza eso:

int f() { try { int i = process(); return i; } catch(Exception ex) { throw new SpecificFault(ex); } }


Use Unity.Interception para limpiar el código. Con el manejo de la intercepción, su código podría verse así:

int f() { // no need to try-catch any more, here or anywhere else... int i = process(); return i; }


Todo lo que necesita hacer en el siguiente paso es definir un controlador de intercepción, que puede personalizar para el manejo de excepciones. Usando este controlador, puedes manejar todas las excepciones lanzadas en tu aplicación. La ventaja es que ya no tienes que marcar todo tu código con bloques try-catch.

public class MyCallHandler : ICallHandler, IDisposable { public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { // call the method var methodReturn = getNext().Invoke(input, getNext); // check if an exception was raised. if (methodReturn.Exception != null) { // take the original exception and raise a new (correct) one... CreateSpecificFault(methodReturn.Exception); // set the original exception to null to avoid throwing yet another // exception methodReturn.Exception = null; } // complete the invoke... return methodReturn; } }

El registro de una clase en el controlador se puede hacer a través de un archivo de configuración, o mediante programación. El código es bastante sencillo. Después del registro, crea una instancia de sus objetos utilizando Unity, como este:

var objectToUse = myUnityContainer.Resolve<MyObjectToUse>();

Más sobre Unity.Interception:

http://msdn.microsoft.com/en-us/library/ff646991.aspx