Domanda

Al momento non ho questo problema , ma non lo sai mai e gli esperimenti sul pensiero sono sempre divertenti.

Ignorando gli ovvi problemi che dovresti avere con la tua architettura anche solo per tentare questo , supponiamo che tu abbia un codice orribilmente scritto del design di qualcun altro e che devi fare un gruppo di operazioni ampie e varie nello stesso blocco di codice, ad esempio:

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

Moltiplicato per cento. Alcuni di questi potrebbero funzionare, altri potrebbero andare molto male. Ciò di cui hai bisogno è l'equivalente C # di "quot on error" per riprendere successivamente ", altrimenti finirai per copiare e incollare i trucchi di prova attorno alle molte righe di codice.

Come tenteresti di affrontare questo problema?

È stato utile?

Soluzione

È abbastanza ovvio che dovresti scrivere il codice in VB.NET, che in realtà ha On Error Resume Next , ed esportalo in una DLL in C #. Tutto il resto è solo un ghiottone  per punizione.

Altri suggerimenti

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

Rifattore in metodi individuali e ben definiti:

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

Ognuno di questi è protetto in modo appropriato.

Direi non fare nulla .

Sì, è vero, non fare NIENTE.

Mi hai chiaramente identificato due cose:

  1. Sai che l'architettura è chiusa.
  2. C'è un sacco di questa merda.

Dico:

  • Non fare nulla.
  • Aggiungi un gestore di errori globale per inviarti un'email ogni volta che diventa boom.
  • Attendi fino a quando qualcosa cade (o fallisce un test)
  • Correggilo (Refactoring se necessario nell'ambito della pagina ).
  • Ripeti ogni volta che si verifica un problema.

Avrai chiarito tutto in pochissimo tempo se è così male. Sì, lo so che sembra schifoso e potresti iniziare a toglierti i capelli con correzioni di bug, ma ti permetterà di correggere il codice bisognoso / buggy prima della (grande) quantità di codice che in realtà potrebbe funzionare non importa quanto sia scadente.

Una volta che inizi a vincere la guerra, avrai una migliore gestione del codice (grazie a tutto il tuo refactoring) avrai un'idea migliore per un design vincente per esso ..

Cercare di avvolgerlo completamente in un involucro di bolle probabilmente richiederà molto tempo e non sarai ancora più vicino a risolvere i problemi.

Fail Fast

Per elaborare, suppongo di mettere in discussione la domanda. Se viene generata un'eccezione, perché vuoi che il tuo codice continui semplicemente come se nulla fosse successo? O ti aspetti eccezioni in determinate situazioni, nel qual caso scrivi un blocco try-catch attorno a quel codice e li gestisci, oppure c'è un errore imprevisto, nel qual caso dovresti preferire che l'applicazione si interrompa, o riprovi o fallisca. Non andare avanti come uno zombi ferito che geme "cervelli".

Questa è una delle cose per cui è utile avere un preprocessore. Puoi definire una macro che ingoia eccezioni, quindi con uno script veloce aggiungi quella macro a tutte le righe.

Quindi, se fosse C ++, potresti fare qualcosa del genere:

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

Sfortunatamente, non molte lingue sembrano includere un preprocessore come C / C ++.

È possibile creare il proprio preprocessore e aggiungerlo come passaggio pre-build. Se ti andasse di automatizzarlo completamente, probabilmente potresti scrivere un preprocessore che prenderebbe il file di codice reale e aggiungerebbe le cose try / catch da solo (quindi non devi aggiungere manualmente quei blocchi ATTEMPT () al codice) . Accertarsi che abbia modificato solo le linee che dovrebbe essere difficile potrebbe essere difficile (è necessario saltare dichiarazioni di variabili, costrutti di loop, ecc. Per non interrompere la build).

Tuttavia, penso che queste siano idee orribili e non dovrebbero mai essere fatte, ma la domanda è stata posta. :)

Davvero, non dovresti mai farlo. Devi trovare la causa dell'errore e risolverlo. Ingoiare / ignorare gli errori è una brutta cosa da fare, quindi penso che la risposta corretta qui sia " Correggi il bug, non ignorarlo! & Quot ;. :)

On Error Resume Next è una pessima idea nel mondo C #. Né aggiungerebbe l'equivalente di On Error Resume Next sarebbe davvero utile. Tutto ciò che farebbe sarebbe lasciarti in un cattivo stato che potrebbe causare errori più sottili, perdita di dati e possibilmente corruzione dei dati.

Ma per dare il dovuto all'interrogatore, potresti aggiungere un gestore globale e controllare TargetSite per vedere quale metodo ha funzionato. Quindi potresti almeno sapere su quale linea ha funzionato. La parte successiva consisterà nel cercare di capire come impostare la "prossima dichiarazione" allo stesso modo del debugger. Spero che il tuo stack non si sia srotolato a questo punto o puoi ricrearlo, ma sicuramente vale la pena provare. Tuttavia, dato questo approccio, il codice dovrebbe essere eseguito ogni volta in modalità Debug in modo da includere i simboli di debug.

Come qualcuno ha menzionato, VB lo consente. Che ne dici di farlo allo stesso modo in C #? Inserisci fidato riflettore:

Questo:

Sub Main()
    On Error Resume Next

    Dim i As Integer = 0

    Dim y As Integer = CInt(5 / i)


End Sub

Traduce in questo:

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

Riscrivi il codice. Prova a trovare una serie di istruzioni che logicamente dipendono l'una dall'altra, in modo che se uno fallisce, le successive non hanno senso, e le danno alle loro stesse funzioni e metti le prove intorno a loro, se vuoi ignorare il risultato di quello e continua.

Questo può aiutarti a identificare i pezzi che presentano il maggior numero di problemi.

@ JB King Grazie per avermi ricordato. Il blocco dell'applicazione Registrazione ha un evento di strumentazione che può essere utilizzato per tracciare gli eventi, è possibile trovare maggiori informazioni sui documenti della libreria MS Enterprise.

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

Tutti i passaggi di questo utilizzo verranno tracciati in un file di registro e puoi analizzarlo per vedere dove si rompe il registro (ex viene gettato) e identificare gli autori di reati elevati.

Il refactoring è davvero la tua scommessa migliore, ma se hai molto, questo può aiutarti a individuare i peggiori trasgressori.

potresti usare goto, ma è ancora disordinato.

In realtà ho voluto una sorta di singola dichiarazione try-catch per un po '. Sarebbe utile in alcuni casi, come l'aggiunta di codice di registrazione o qualcosa che non si desidera interrompere il flusso del programma principale se fallisce.

Sospetto che si potrebbe fare qualcosa con alcune delle funzionalità associate a Linq, ma al momento non ho davvero il tempo di esaminarlo. Se solo riuscissi a trovare un modo per racchiudere un'istruzione come una funzione anonima, quindi usane un'altra per chiamare che all'interno di un blocco try-catch funzionerebbe ... ma non sei sicuro che sia possibile ancora.

Se riesci a far sì che il compilatore ti dia un albero delle espressioni per questo codice, puoi modificare tale albero delle espressioni sostituendo ogni istruzione con un nuovo blocco try-catch che avvolge l'istruzione originale. Questo non è inverosimile come sembra; per LINQ, C # ha acquisito la capacità di acquisire espressioni lambda come alberi di espressioni che possono essere manipolati nel codice utente in fase di esecuzione.

Questo approccio non è possibile oggi con .NET 3.5 - se non altro per la mancanza di un "prova" istruzione in System.Linq.Expressions. Tuttavia, potrebbe benissimo essere praticabile in una versione futura di C # una volta completata l'unione degli alberi delle espressioni DLR e LINQ.

Perché non usare il riflesso in c #? È possibile creare una classe che si riflette sul codice e utilizzare le righe # come suggerimento per cosa inserire in ogni singolo blocco try / catch. Questo ha alcuni vantaggi:

  1. È leggermente meno brutto in quanto in realtà non è necessario manipolare il codice sorgente e puoi usarlo solo durante le modalità di debug.
  2. Impara qualcosa di interessante su c # mentre lo implementi.

Vorrei tuttavia sconsigliare qualsiasi cosa, a meno che, naturalmente, non si prenda in carico la manutenzione di alcunielsels e non si debba gestire le eccezioni in modo da poterle correggere. Potrebbe essere divertente scrivere però.

Domanda divertente; molto terribile.

Sarebbe bello se tu potessi usare una macro. Ma questo è un C # distrutto, quindi potresti risolverlo con qualche lavoro di preprocessore o qualche strumento esterno per avvolgere le tue linee in singoli blocchi try-catch. Non sono sicuro se volevi dire che non volevi manualmente avvolgerli o che volevi evitare di provare a catturare interamente .

Facendo casino con questo, ho provato a etichettare ogni riga e saltare indietro da una singola cattura, senza molta fortuna. Tuttavia, Christopher ha scoperto il corretto modo per farlo . C'è qualche interessanti discussioni aggiuntive di questo in Dot Net Thoughts e in Blog di Mike Stall. .

EDIT: certo. La soluzione try-catch / switch-goto elencata in realtà non verrà compilata poiché le etichette try non rientrano nell'ambito in cattura . Qualcuno sa cosa manca per fare qualcosa di simile a questa compilazione?

Potresti automatizzare questo con una fase di pre-elaborazione del compilatore o magari hackerare Strumento Inline IL di Mike Stall per iniettare un po 'di ignoranza nell'errore.

( Orion Adrian's la risposta sull'esame dell'eccezione e anche sul tentativo di impostare le istruzioni successive è interessante.)

Tutto sommato, sembra un esercizio interessante e istruttivo. Ovviamente, dovresti decidere a che punto lo sforzo di simulare ON ERROR RESUME NEXT supera lo sforzo di correggere il codice. : -)

Cattura gli errori in Evento UnhandledException dell'applicazione. In questo modo, le esecuzioni non gestite possono anche essere registrate al mittente e qualsiasi altra informazione lo sviluppatore ritenga ragionevole.

Sfortunatamente probabilmente sei sfortunato. Su errore Riprendi Next è un'opzione legacy che è generalmente fortemente scoraggiata e non ha un equivalente delle mie conoscenze in C #.

Vorrei raccomandare di lasciare il codice in VB (sembra che fosse la fonte, data la tua specifica richiesta per OnError ResumeNext) e di interfacciarmi con o da una DLL C # o exe che implementa qualunque nuovo codice ti serva. Quindi preforma il refactoring per rendere sicuro il codice e converti questo codice sicuro in C # mentre lo fai.

Potresti esaminare l'integrazione del componente Gestione delle eccezioni di Enterprise Library per avere un'idea di come gestire le eccezioni non gestite.

Se questo è per le applicazioni ASP.Net, c'è una funzione in Global.asax chiamata, " Application_Error " che viene chiamato nella maggior parte dei casi con fallimento catastrofico che è l'altro caso di solito.

Ignorando tutti i motivi per cui vorresti evitare di farlo .......

Se fosse semplicemente necessario mantenere il numero di righe in basso, potresti provare qualcosa del tipo:

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

Tuttavia, dovresti tenere d'occhio l'ambito variabile se provi a riutilizzare uno qualsiasi dei risultati delle chiamate.

Hilite ogni riga, una alla volta, "Surround with" try / catch. Ciò evita l'incollamento della copia che hai citato

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top