Question

Je n'ai pas actuellement ce problème , mais on ne sait jamais et les expériences sont toujours amusantes.

Ignorant les problèmes évidents que vous auriez à résoudre avec votre architecture avant même d'essayer cela , supposons que vous disposiez d'un code horriblement écrit de la conception de quelqu'un d'autre et que vous deviez tas d'opérations larges et variées dans le même bloc de code, par exemple:

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

Multiplié par cent. Certaines d’entre elles pourraient fonctionner, d’autres pourraient mal tourner. Ce dont vous avez besoin, c’est l’équivalent C # de "suite d’une erreur à la suite de", sinon vous finirez par copier et coller des captures d’essai autour des nombreuses lignes de code.

Comment tenteriez-vous de résoudre ce problème?

Était-ce utile?

La solution

Il est assez évident que vous écriviez le code dans VB.NET, qui contient en réalité On Error Resume Next et exportez-le dans une DLL au format C #. Tout le reste n'est que glouton  pour punition.

Autres conseils

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 );

Refactoriser en méthodes individuelles bien nommées:

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

Chacun de ceux-ci est protégé de manière appropriée.

Je dirais ne rien faire .

Ouais c'est vrai, ne rien faire.

Vous m'avez clairement identifié deux choses:

  1. Vous savez que l'architecture est bouleversée.
  2. Il y a une tonne de cette merde.

Je dis:

  • Ne rien faire.
  • Ajoutez un gestionnaire d'erreurs global pour vous envoyer un courrier électronique chaque fois que cela se produira.
  • Attendez que quelque chose tombe (ou échoue à un test)
  • Corrigez cela (refactoring si nécessaire dans le cadre de la page ).
  • Répétez chaque fois qu'un problème survient.

Vous aurez cette information en un rien de temps si c'est aussi grave. Oui, je sais que cela semble insipide et que vous pourriez peut-être vous tromper de cheveux avec des corrections de bugs, mais cela vous permettra de corriger le code des nécessiteux / des bogues avant la (grande) quantité de code . cela peut effectivement fonctionner , peu importe à quel point il a l'air minable.

Une fois que vous commencerez à gagner la guerre, vous aurez une meilleure connaissance du code (grâce à tous vos refactoring), vous aurez une meilleure idée de la conception gagnante pour celui-ci.

Essayer de tout mettre dans du papier bulle ne va probablement prendre que très longtemps et vous ne serez toujours pas près de résoudre les problèmes.

échec rapide

Pour élaborer, je suppose que je remets en question la question. Si une exception est levée, pourquoi voudriez-vous que votre code continue simplement comme si rien ne s'était passé? Soit vous vous attendez à des exceptions dans certaines situations, auquel cas vous écrivez un bloc try-catch autour de ce code et vous les gérez, soit il existe une erreur inattendue. Dans ce cas, vous devriez préférer que votre application soit abandonnée, réessayée ou en échec. Ne pas continuer comme un zombie blessé qui gémit «le cerveau».

C’est l’une des choses pour lesquelles le préprocesseur est utile. Vous pouvez définir une macro engloutissant les exceptions, puis ajouter un script rapide à toutes les lignes.

Donc, si c'était du C ++, vous pourriez faire quelque chose comme ça:

#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);

Malheureusement, peu de langues semblent inclure un préprocesseur comme C / C ++.

Vous pouvez créer votre propre préprocesseur et l'ajouter en tant qu'étape de pré-génération. Si vous avez envie d'automatiser complètement ce processus, vous pouvez probablement écrire un préprocesseur qui prendrait le fichier de code lui-même et ajoutera lui-même le contenu try / catch (vous n'aurez donc pas à ajouter manuellement les blocs ATTEMPT () au code). . S'assurer qu'il ne modifie que les lignes qu'il est censé modifier pourrait cependant être difficile (il faut ignorer les déclarations de variable, les constructions en boucle, etc. pour que vous ne cassiez pas la construction).

Cependant, je pense que ce sont des idées horribles et ne devraient jamais être faites, mais la question a été posée. :)

Vraiment, vous ne devriez jamais faire cela. Vous devez trouver la cause de l'erreur et la corriger. Avaler / ignorer les erreurs est une mauvaise chose à faire. Je pense donc que la réponse correcte est la suivante: "Corrigez le bogue, ne l'ignorez pas!". :)

On Error Resume Next est une très mauvaise idée dans le monde C #. Ajouter l'équivalent à On Error Resume Next ne vous aiderait pas non plus. Tout ce que cela ferait serait de vous laisser dans un mauvais état, ce qui pourrait provoquer des erreurs plus subtiles, des pertes de données et éventuellement une corruption des données.

Mais pour donner à l'auteur de la question son dû, vous pouvez ajouter un gestionnaire global et vérifier le TargetSite pour voir quelle méthode est bloquée. Ensuite, vous pourriez au moins savoir sur quelle ligne il bouge. La partie suivante consisterait à essayer de comprendre comment définir le "prochain énoncé". de la même manière que le débogueur le fait. Espérons que votre pile ne se sera pas déroulée à ce stade ou que vous pourrez la recréer, mais cela vaut certainement le coup. Cependant, étant donné cette approche, le code devrait être exécuté en mode débogage à chaque fois pour que vos symboles de débogage soient inclus.

Comme l’a mentionné une personne, VB le permet. Pourquoi ne pas le faire de la même manière en C #? Entrez un réflecteur fiable:

Ceci:

Sub Main()
    On Error Resume Next

    Dim i As Integer = 0

    Dim y As Integer = CInt(5 / i)


End Sub

traduit en ceci:

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();
    }
}

Réécrivez le code. Essayez de trouver des ensembles d'instructions qui dépendent logiquement les uns des autres, de sorte qu'en cas d'échec, les suivants n'ont aucun sens, et de les intégrer à leurs propres fonctions et de placer des tentatives d'essais autour d'eux, si vous voulez ignorer le résultat de ça et continue.

Cela peut vous aider à identifier les pièces qui posent le plus de problèmes.

@ JB King Merci de me le rappeler. Le bloc d'application Journalisation contient un événement d'instrumentation qui peut être utilisé pour suivre les événements. Vous pouvez trouver plus d'informations sur les documents de la bibliothèque MS Enterprise.

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

Toutes les étapes de cette utilisation seront tracées dans un fichier journal et vous pourrez les analyser pour voir où le journal est cassé (ex est jeté) et identifier les auteurs d'infractions graves.

Le refactoring est vraiment votre meilleur choix, mais si vous en avez beaucoup, cela peut vous aider à identifier les pires contrevenants.

Vous pouvez utiliser la méthode goto, mais cela reste compliqué.

Je voulais en fait une sorte de déclaration unique qui tente d’attraper quelque chose. Cela serait utile dans certains cas, comme l'ajout de code de journalisation ou quelque chose que vous ne voulez pas interrompre le flux du programme principal s'il échoue.

Je soupçonne que quelque chose pourrait être faite avec certaines des fonctionnalités associées à linq, mais je n’ai pas vraiment le temps de les étudier pour le moment. Si vous pouviez trouver un moyen de transformer une instruction en une fonction anonyme, utilisez-en une autre pour appeler cela dans un bloc try-catch, cela fonctionnerait ... mais vous ne savez pas si cela est possible pour l'instant.

Si vous pouvez demander au compilateur de vous fournir un arbre d’expression pour ce code, vous pouvez le modifier en remplaçant chaque instruction par un nouveau bloc try-catch qui encapsule l’instruction originale. Ce n'est pas aussi exagéré que cela puisse paraître; pour LINQ, C # a acquis la capacité de capturer les expressions lambda sous forme d’arbres d’expression pouvant être manipulés dans le code utilisateur au moment de l’exécution.

Cette approche n’est pas possible aujourd’hui avec .NET 3.5 - ne serait-ce que pour l’absence de " try " déclaration dans System.Linq.Expressions. Cependant, il est fort possible que cela soit viable dans une future version de C # une fois la fusion des arborescences d’expression DLR et LINQ terminée.

Pourquoi ne pas utiliser le reflet dans c #? Vous pouvez créer une classe qui réfléchit sur le code et utiliser la ligne # comme indice pour indiquer ce qu'il faut mettre dans chaque bloc try / catch. Cela présente quelques avantages:

  1. C'est un peu moins moche, car vous n'avez pas vraiment besoin de modifier votre code source et vous ne pouvez l'utiliser que pendant les modes de débogage.
  2. Vous apprenez quelque chose d'intéressant à propos de c # lors de son implémentation.

Cependant, je vous déconseillerais cette solution, sauf si vous prenez bien sûr en charge la maintenance de certaines tâches et que vous devez maîtriser les exceptions pour pouvoir les corriger. Ce serait peut-être amusant d’écrire.

Question amusante; très terrible.

Ce serait bien si vous pouviez utiliser une macro. Mais comme il s’agit d’un fichier C # éclaté, vous pouvez le résoudre avec un travail de pré-traitement ou un outil externe pour encapsuler vos lignes dans des blocs try-catch individuels. Vous ne savez pas vraiment si vous ne voulez pas les emballer manuellement ou si vous voulez éviter d'essayer d'attraper entièrement .

Avec ça, j’ai essayé de marquer chaque ligne et de sauter d’une prise à l’autre, sans trop de chance. Cependant, Christopher a découvert le correct manière de le faire . Il existe des discussions supplémentaires intéressantes. de cela à Dot Net Thoughts et à Blog .NET de Mike Stall .

EDIT: Bien sûr. La solution try-catch / switch-goto répertoriée ne sera pas compilée car les étiquettes try sont hors de portée dans . attraper . Quelqu'un sait ce qui manque pour faire quelque chose comme cette compilation?

Vous pouvez automatiser cela avec une étape de prétraitement du compilateur ou peut-être pirater L’outil en ligne IL de Mike Stall pour injecter de l’ignorance par erreur.

( Orion Adrian's répondre à l’examen de l’exception et à la définition de l’instruction suivante est également intéressant.)

Dans l’ensemble, c’est un exercice intéressant et instructif. Bien entendu, il vous faudra décider à quel moment l'effort de simulation de ON ERROR RESUME NEXT l'emporte sur celui de correction du code. : -)

Catch les erreurs dans le Evénement UnhandledException de l'application. De cette façon, les exécutions non gérées peuvent même être consignées pour l'expéditeur et pour toute autre information que le développeur pourrait avoir.

Malheureusement, vous n'avez probablement pas de chance. On Error Resume Next est une option héritée qui est généralement fortement déconseillée et n’a pas d’équivalent à mes connaissances en C #.

Je recommanderais de laisser le code en VB (cela ressemble apparemment à la source, compte tenu de votre demande spécifique pour OnError ResumeNext) et à l'interfaçage avec ou à partir d'une dll ou d'un exe C # qui implémente le nouveau code dont vous avez besoin. Effectuez ensuite un refactoring afin de rendre le code sûr et convertissez ce code sécurisé en C # en procédant de la sorte.

Vous pourriez envisager d'intégrer le composant de traitement des exceptions de la bibliothèque d'entreprise pour une idée de la gestion des exceptions non gérées.

S'il s'agit d'applications ASP.Net, il existe une fonction dans le fichier Global.asax appelée "Application_Error". qui est appelé dans la plupart des cas avec une défaillance catastrophique étant l’autre cas habituellement.

En ignorant toutes les raisons pour lesquelles vous voudriez éviter de le faire .......

S'il s'agissait simplement de limiter le nombre de lignes, vous pourriez essayer quelque chose du type:

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

Cependant, vous devez garder un œil sur la portée des variables si vous essayez de réutiliser les résultats des appels.

Hilite chaque ligne, une à la fois, "Entourez avec" try / catch. Cela évite le copier-coller que vous avez mentionné

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top