Pregunta

Actualmente no tengo este problema, pero nunca se sabe y los experimentos mentales siempre son divertidos.

Ignorando los problemas obvios que tendría que tener con su arquitectura para siquiera intentar esto, supongamos que tenía un código horriblemente escrito diseñado por otra persona y necesitaba realizar un montón de operaciones amplias y variadas en el mismo bloque de código, por ejemplo:

WidgetMaker.SetAlignment(57);
contactForm["Title"] = txtTitle.Text;
Casserole.Season(true, false);
((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;

Multiplicado por cien.Algunas de ellas podrían funcionar, otras podrían salir muy mal.Lo que necesita es el equivalente en C# de "en caso de error, reanudar a continuación", de lo contrario, terminará copiando y pegando intentos de captura en las muchas líneas de código.

¿Cómo intentaría abordar este problema?

¿Fue útil?

Solución

Es bastante obvio que escribirías el código en VB.NET, que en realidad tiene En caso de error Continuar siguiente, y exportarlo en una DLL a C#.Cualquier otra cosa es ser un glotón para el castigo.

Otros consejos

public delegate void VoidDelegate();

public static class Utils
{
  public static void Try(VoidDelegate v) {
    try {
      v();
    }
    catch {}
  }
}

Utils.Try( () => WidgetMaker.SetAlignment(57) );
Utils.Try( () => contactForm["Title"] = txtTitle.Text );
Utils.Try( () => Casserole.Season(true, false) );
Utils.Try( () => ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true );

Refactorice en métodos individuales y bien nombrados:

AdjustFormWidgets();
SetContactTitle(txtTitle.Text);
SeasonCasserole();

Cada uno de ellos está protegido adecuadamente.

yo diría hacer nada.

Sí, así es, no hagas NADA.

Me has identificado claramente dos cosas:

  1. Sabes que la arquitectura está aburrida.
  2. Hay un montón de esta basura.

Yo digo:

  • Hacer nada.
  • Agregue un controlador de errores global para enviarle un correo electrónico cada vez que suene.
  • Espere hasta que algo se caiga (o falle una prueba)
  • Corrija eso (Refactorizando según sea necesario dentro del alcance de la página).
  • Repita cada vez que ocurra un problema.

Esto lo solucionarás en poco tiempo si es tan malo.Sí, sé que suena horrible y es posible que para empezar te estés tirando de los pelos con correcciones de errores, pero te permitirá arregle el código necesitado/con errores antes la (gran) cantidad de código que realmente puede estar funcionando por muy cutre que parezca.

Una vez que comiences a ganar la guerra, tendrás un mejor manejo del código (debido a toda tu refactorización), tendrás una mejor idea para un diseño ganador.

Intentar envolverlo todo en plástico de burbujas probablemente llevará mucho tiempo y aún no estará más cerca de solucionar los problemas.

Fallar rapido

Para dar más detalles, supongo que estoy cuestionando la pregunta.Si se produce una excepción, ¿por qué querrías que tu código simplemente continúe como si nada hubiera pasado?O esperas excepciones en ciertas situaciones, en cuyo caso escribes un bloque try-catch alrededor de ese código y las manejas, o hay un error inesperado, en cuyo caso deberías preferir que tu aplicación aborte, reintente o falle.No seguir como un zombi herido gimiendo "cerebros".

Esta es una de las cosas para las que resulta útil tener un preprocesador.Podría definir una macro que acepte excepciones y luego, con un script rápido, agregar esa macro a todas las líneas.

Entonces, si esto fuera C++, podrías hacer algo como esto:

#define ATTEMPT(x) try { x; } catch (...) { }
// ...
ATTEMPT(WidgetMaker.SetAlignment(57));
ATTEMPT(contactForm["Title"] = txtTitle.Text);
ATTEMPT(Casserole.Season(true, false));
ATTEMPT(((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true);

Desafortunadamente, no muchos lenguajes parecen incluir un preprocesador como lo hizo C/C++.

Puede crear su propio preprocesador y agregarlo como paso previo a la compilación.Si desea automatizarlo por completo, probablemente podría escribir un preprocesador que tomaría el archivo de código real y agregaría las cosas try/catch por sí solo (para que no tenga que agregar esos bloques ATTEMPT() al código manualmente) .Sin embargo, asegurarse de que solo modifique las líneas que se supone que debe hacer podría ser difícil (debe omitir declaraciones de variables, construcciones de bucle, etc. para no romper la compilación).

Sin embargo, creo que estas son ideas horribles y nunca deberían hacerse, pero se formuló la pregunta.:)

Realmente, nunca deberías hacer esto.Debe encontrar la causa del error y solucionarlo.Tragar/ignorar errores es algo malo, así que creo que correcto La respuesta aquí es "¡Corrija el error, no lo ignore!".:)

On Error Resume Next Es una muy mala idea en el mundo C#.Tampoco añadir el equivalente a On Error Resume Next realmente te ayuda.Todo lo que haría es dejarlo en mal estado, lo que podría causar errores más sutiles, pérdida de datos y posiblemente corrupción de datos.

Pero para darle lo que le corresponde al interrogador, puede agregar un controlador global y verificar TargetSite para ver qué método funcionó.Entonces al menos podrías saber en qué línea funciona.La siguiente parte sería intentar descubrir cómo configurar la "siguiente declaración" de la misma manera que lo hace el depurador.Con suerte, tu pila no se habrá desenrollado en este punto o podrás volver a crearla, pero ciertamente vale la pena intentarlo.Sin embargo, dado este enfoque, el código tendría que ejecutarse en modo de depuración cada vez para que se incluyan los símbolos de depuración.

Como alguien mencionó, VB permite esto.¿Qué tal hacerlo de la misma manera en C#?Ingrese el reflector confiable:

Este:

Sub Main()
    On Error Resume Next

    Dim i As Integer = 0

    Dim y As Integer = CInt(5 / i)


End Sub

Se traduce en esto:

public static void Main()
{
    // This item is obfuscated and can not be translated.
    int VB$ResumeTarget;
    try
    {
        int VB$CurrentStatement;
    Label_0001:
        ProjectData.ClearProjectError();
        int VB$ActiveHandler = -2;
    Label_0009:
        VB$CurrentStatement = 2;
        int i = 0;
    Label_000E:
        VB$CurrentStatement = 3;
        int y = (int) Math.Round((double) (5.0 / ((double) i)));
        goto Label_008F;
    Label_0029:
        VB$ResumeTarget = 0;
        switch ((VB$ResumeTarget + 1))
        {
            case 1:
                goto Label_0001;

            case 2:
                goto Label_0009;

            case 3:
                goto Label_000E;

            case 4:
                goto Label_008F;

            default:
                goto Label_0084;
        }
    Label_0049:
        VB$ResumeTarget = VB$CurrentStatement;
        switch (((VB$ActiveHandler > -2) ? VB$ActiveHandler : 1))
        {
            case 0:
                goto Label_0084;

            case 1:
                goto Label_0029;
        }
    }
    catch (object obj1) when (?)
    {
        ProjectData.SetProjectError((Exception) obj1);
        goto Label_0049;
    }
Label_0084:
    throw ProjectData.CreateProjectError(-2146828237);
Label_008F:
    if (VB$ResumeTarget != 0)
    {
        ProjectData.ClearProjectError();
    }
}

Reescribe el código.Intente encontrar conjuntos de declaraciones que dependan lógicamente unas de otras, de modo que si una falla, las siguientes no tengan sentido, y divídalas en sus propias funciones y colóquelas con try-catches, si desea ignorar el resultado de eso y continuar.

Esto puede ayudarle a identificar las piezas que tienen más problemas.

@ JB King Gracias por recordarme.El bloque de aplicación de registro tiene un evento de instrumentación que se puede usar para rastrear eventos; puede encontrar más información en los documentos de la biblioteca de MS Enterprise.

Using (New InstEvent)
<series of statements> 
End Using

Todos los pasos de este uso se rastrearán hasta un archivo de registro, y usted puede analizarlo para ver dónde se rompe el registro (se arroja el ex) e identificar a los infractores graves.

La refactorización es realmente tu mejor opción, pero si tienes muchas, esto puede ayudarte a identificar a los peores infractores.

podría usa goto, pero sigue siendo complicado.

De hecho, hace tiempo que quería una especie de try-catch de declaración única.Sería útil en ciertos casos, como agregar código de registro o algo que no desee interrumpir el flujo principal del programa si falla.

Sospecho que se podría hacer algo con algunas de las funciones asociadas con linq, pero no tengo tiempo para investigarlo en este momento.Si pudiera encontrar una manera de envolver una declaración como una función anónima, luego usar otra para llamarla dentro de un bloque try-catch, funcionaría...pero no estoy seguro de si eso es posible todavía.

Si puede lograr que el compilador le brinde un árbol de expresión para este código, entonces podría modificar ese árbol de expresión reemplazando cada declaración con un nuevo bloque try-catch que envuelva la declaración original.Esto no es tan descabellado como parece;para LINQ, C# adquirió la capacidad de capturar expresiones lambda como árboles de expresión que pueden manipularse en el código de usuario en tiempo de ejecución.

Este enfoque no es posible hoy en día con .NET 3.5, aunque sólo sea por la falta de una declaración "try" en System.Linq.Expressions.Sin embargo, es muy posible que sea viable en una versión futura de C# una vez que se complete la combinación de los árboles de expresión DLR y LINQ.

¿Por qué no utilizar la reflexión en C#?Puede crear una clase que refleje el código y usar los números de línea como sugerencia sobre qué poner en cada bloque try/catch individual.Esto tiene algunas ventajas:

  1. Es un poco menos feo ya que en realidad no es necesario alterar el código fuente y solo puedes usarlo durante los modos de depuración.
  2. Aprende algo interesante sobre C# mientras lo implementa.

Sin embargo, recomendaría no hacer nada de esto, a menos, por supuesto, que usted se haga cargo del mantenimiento del trabajo de otra persona y necesite controlar las excepciones para poder solucionarlas.Aunque podría ser divertido escribirlo.

Pregunta divertida;muy terrible.

Sería bueno si pudieras usar una macro.Pero esto es C#, por lo que puedes resolverlo con algo de trabajo de preprocesador o alguna herramienta externa para encapsular tus líneas en bloques try-catch individuales.No estoy seguro si quisiste decir que no querías a mano envuélvelos o que querías evitar try-catch enteramente.

Jugando con esto, intenté etiquetar cada línea y saltar hacia atrás desde una sola captura, sin mucha suerte.Sin embargo, Christopher descubrió la forma correcta de hacer esto..Hay algo interesante discusión adicional sobre esto en Dot Net Thoughts y en Blog .NET de Mike Stall.

EDITAR:Por supuesto.El try-catch / switch-goto La solución enumerada en realidad no se compilará desde el try las etiquetas están fuera del alcance en catch.¿Alguien sabe qué falta para compilar algo como esto?

Podrías automatizar esto con un paso de preproceso del compilador o tal vez hackearlo. Herramienta de IL en línea de Mike Stall para inyectar algo de ignorancia de errores.

(La respuesta de Orion Adrian sobre examinar la excepción y tratar de configurar la siguiente instrucción también es interesante).

Considerándolo todo, parece un ejercicio interesante e instructivo.Por supuesto, tendría que decidir en qué punto el esfuerzo para simular ON ERROR RESUME NEXT supera el esfuerzo para corregir el código.:-)

Detectar los errores en el Evento de excepción no controlado de la aplicación.De esa manera, las excepciones no controladas pueden incluso registrarse en cuanto al remitente y cualquier otra información que el desarrollador considere razonable.

Desafortunadamente, probablemente no tengas suerte.On Error Resume Next es una opción heredada que generalmente no se recomienda y no tiene un equivalente a mis conocimientos en C#.

Recomendaría dejar el código en VB (parece que esa era la fuente, dada su solicitud específica de OnError ResumeNext) e interactuar con o desde un dll o exe de C# que implemente cualquier código nuevo que necesite.Luego, realice la refactorización para que el código sea seguro y convierta este código seguro a C# mientras lo hace.

Podría considerar la integración del componente Manejo de excepciones de Enterprise Library para tener una idea de cómo manejar excepciones no controladas.

Si esto es para aplicaciones ASP.Net, hay una función en Global.asax llamada "Application_Error" que se llama en la mayoría de los casos, siendo el otro caso una falla catastrófica.

Ignorando todas las razones por las que querrías evitar hacer esto...

Si fuera simplemente una necesidad mantener bajo el número de líneas, podría intentar algo como:

int totalMethodCount = xxx;
for(int counter = 0; counter < totalMethodCount; counter++) {
    try {
        if (counter == 0) WidgetMaker.SetAlignment(57);
        if (counter == 1) contactForm["Title"] = txtTitle.Text;
        if (counter == 2) Casserole.Season(true, false);
        if (counter == 3) ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;
    } catch (Exception ex) {
        // log here
    }
}

Sin embargo, deberá estar atento al alcance de la variable si intenta reutilizar cualquiera de los resultados de las llamadas.

Seleccione cada línea, una a la vez, 'Rodear con' intentar/capturar.Eso evita el copiar y pegar que mencionaste.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top