Domanda

Lavorare su un progetto in cui un insieme sequenziale di metodi deve essere eseguito ogni x secondi. In questo momento ho i metodi contenuti in un altro "metodo genitore", e li chiamo sequenzialmente subito dopo l'altro.

class DoTheseThings()
{
    DoThis();
    NowDoThat();
    NowDoThis();
    MoreWork();
    AndImSpent();
}

Ogni metodo deve essere eseguito correttamente senza generare un'eccezione prima di poter eseguire il passaggio successivo. Quindi ora ho inserito ciascuno di questi metodi con un mentre e try..catch , quindi nel catch eseguo di nuovo quel metodo.

while( !hadError )
{
    try
    {
         DoThis();
    }
    catch(Exception doThisException )
    {
         hadError = true;
    }

}

Sembra puzzolente e non molto secco. C'è un modo migliore per farlo, quindi non sto avvolgendo alcuna nuova funzionalità negli stessi metodi. Un qualche tipo di raccolta di delegati non è il modo corretto di implementarlo?

Esiste un altro "corretto" soluzione?

È stato utile?

Soluzione

Action[] work=new Action[]{new Action(DoThis),   new Action(NowDoThat),    
    new Action(NowDoThis),    new Action(MoreWork),    new Action(AndImSpent)};
int current =0;
while(current!=work.Length)
{
   try
   {
      work[current]();
      current++;
   }
   catch(Exception ex)
   {
      // log the error or whatever
      // maybe sleep a while to not kill the processors if a successful execution depends on time elapsed  
   }
}

Altri suggerimenti

  

Una specie di raccolta di delegati non è il modo corretto di implementarla?

Delegare è un modo possibile per risolvere questo problema.

Crea un delegato come:

  

delegato pubblico void WorkDelegate ();

e inseriscili nell'arraylist su cui puoi iterare.

Ho una convinzione religiosa personale che non dovresti catturare System.Exception o, più precisamente, dovresti solo cogliere le eccezioni che sai come gestire.

Detto questo, suppongo che ognuno dei metodi che stai chiamando stia facendo qualcosa di diverso e potrebbe comportare il lancio di diverse eccezioni. Ciò significa che probabilmente dovrai avere gestori diversi per ciascun metodo.

Se segui anche la mia religione e la seconda affermazione è vera, non stai ripetendo il codice inutilmente. A meno che tu non abbia altri requisiti, i miei consigli per migliorare il tuo codice sarebbero:

1) Inserisci il try-catch in ciascun metodo, non attorno a ciascuna chiamata di metodo.

2) Le catture all'interno di ciascun metodo catturano SOLO le eccezioni che conosci.

http://blogs.msdn.com/fxcop /archive/2006/06/14/631923.aspx http://blogs.msdn.com/oldnewthing/archive/ 2005/01/14 / 352949.aspx http://www.joelonsoftware.com/articles/Wrong.html

HTH ...

il tuo esempio sembra ok .. è secco ma farà bene il lavoro !! in realtà se questi metodi eseguono l'accesso db .. puoi usare la transazione per garantire l'integrità ...

se hai a che fare con variabili condivise per programmi multi threader .. è più pulito usare la sincronizzazione .. la cosa più importante nella codifica è che scrivi il codice corretto ... che ha meno bug .. e farà il compito correttamente ..

public void DoTheseThings()
{
    SafelyDoEach( new Action[]{
        DoThis,
        NowDoThat,
        NowDoThis,
        MoreWork,
        AndImSpent
    })
}

public void SafelyDoEach( params Action[] actions )
{
    try
    {
        foreach( var a in actions )
            a();
    }
    catch( Exception doThisException )
    {
        // blindly swallowing every exception like this is a terrible idea
        // you should really only be swallowing a specific MyAbortedException type
        return;
    }
}

Quale potrebbe essere la ragione per cui si è verificato un errore?

Se si trattasse di un problema di risorse, come l'accesso a qualcosa come una connessione o un oggetto, allora potresti voler guardare usando monitor, semafori o semplicemente bloccare.

lock (resource) 
{
    Dosomething(resource);
}

In questo modo se un metodo precedente accede alla risorsa, è possibile attendere fino al rilascio della risorsa per continuare.

Idealmente, non dovresti dover eseguire un ciclo per eseguire qualcosa ogni volta che fallisce. Non riesce affatto, vorresti sapere il problema e risolverlo. Avere un ciclo per continuare a provare sempre non è il modo giusto per andare qui.

Farei quello che Ovidiu Pacurar suggerisce, solo userei un ciclo foreach e lascerei a che fare con gli indici di array fino al compilatore.

Approccio delegato semplice:

Action<Action> tryForever = (action) => { 
   bool success;
   do {
     try {
       action();
       success = true;
     } catch (Exception) {
       // should probably log or something here...
     }
   } while (!success);
};

void DoEverything() {
   tryForever(DoThis);
   tryForever(NowDoThat);
   tryForever(NowDoThis);
   tryForever(MoreWork);
   tryForever(AndImSpent);
}

Approccio stack:

void DoEverything() {
  Stack<Action> thingsToDo = new Stack<Action>(
    new Action[] { 
      DoThis, NowDoThat, NowDoThis, MoreWork, AndImSpent 
    }
  );

  Action action;
  while ((action = thingsToDo.Pop()) != null) {
     bool success;
     do {
       try {
         action();
         success = true;
       } catch (Exception) {
       }
     } while (!success);
  }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top