Redusere duplikat feilhåndtering kode i C #?

stemmer
33

Jeg har aldri vært helt fornøyd med måten unntak håndtering fungerer, det er mye unntak og prøve / fangst bringer til bordet (stable avkobling, etc.), men det ser ut til å bryte mye av OO modell i prosessen.

Uansett, her er problemet:

La oss si at du har noen klasse som brytes eller omfatter nettverks fil IO operasjoner (f.eks lesing og skriving til noen fil på noen spesiell UNC-banen et sted). Av ulike grunner til at du ikke vil at disse IO operasjoner for å mislykkes, så hvis du oppdager at de ikke klarer du prøve dem, og du holde prøver på nytt dem før de lykkes eller du når en timeout. Jeg har allerede en praktisk RetryTimer klasse som jeg kan instantiate og brukes til å sove gjeldende tråd mellom forsøk og bestemmer når avbruddsperioden har utløpt, etc.

Problemet er at du har en haug med IO operasjoner i flere metoder i denne klassen, og du trenger å pakk hver av dem i prøve-fangst / retry logikk.

Her er et eksempel kodebit:

RetryTimer fileIORetryTimer = new RetryTimer(TimeSpan.FromHours(10));
bool success = false;
while (!success)
{
    try
    {
        // do some file IO which may succeed or fail
        success = true;
    }
    catch (IOException e)
    {
        if (fileIORetryTimer.HasExceededRetryTimeout)
        {
            throw e;
        }
        fileIORetryTimer.SleepUntilNextRetry();
    }
}

Så, hvordan kan du unngå å duplisere det meste av denne koden for hver fil IO drift hele klassen? Min løsning var å bruke anonyme delegere blokker og en enkelt metode i klassen som kjøres representanten blokk gått til det. Dette tillater meg å gjøre ting som dette i andre metoder:

this.RetryFileIO( delegate()
    {
        // some code block
    } );

Jeg liker denne noe, men det overlater mye å være ønsket. Jeg vil gjerne høre hvordan andre mennesker ville løse denne typen problem.

Publisert på 04/08/2008 klokken 19:21
kilden bruker
På andre språk...                            


4 svar

stemmer
13

Dette ser ut som en utmerket mulighet til å ta en titt på Aspect Oriented Programming. Her er en god artikkel om AOP i .NET . Den generelle ideen er at du vil trekke ut tverrfaglig bekymring (dvs. Prøv igjen for x timer) i en egen klasse, og da bør du kommentere noen metoder som trenger å endre sin atferd på den måten. Her er hvordan det kan se ut (med en fin forlengelse metode på Int32)

[RetryFor( 10.Hours() )]
public void DeleteArchive()
{
  //.. code to just delete the archive
}
Svarte 05/08/2008 kl. 09:43
kilden bruker

stemmer
4

Bare lurer, hva føler du din metode forlater ønsket? Du kan erstatte den anonyme representanten med en .. heter? delegere, noe som

    public delegate void IoOperation(params string[] parameters);

    public void FileDeleteOperation(params string[] fileName)
    {
        File.Delete(fileName[0]);
    }

    public void FileCopyOperation(params string[] fileNames)
    {
        File.Copy(fileNames[0], fileNames[1]);
    }

    public void RetryFileIO(IoOperation operation, params string[] parameters)
    {
        RetryTimer fileIORetryTimer = new RetryTimer(TimeSpan.FromHours(10));
        bool success = false;
        while (!success)
        {
            try
            {
                operation(parameters);
                success = true;
            }
            catch (IOException e)
            {
                if (fileIORetryTimer.HasExceededRetryTimeout)
                {
                    throw;
                }
                fileIORetryTimer.SleepUntilNextRetry();
            }
        }
    }

    public void Foo()
    {
        this.RetryFileIO(FileDeleteOperation, "L:\file.to.delete" );
        this.RetryFileIO(FileCopyOperation, "L:\file.to.copy.source", "L:\file.to.copy.destination" );
    }
Svarte 04/08/2008 kl. 20:07
kilden bruker

stemmer
2

Her er hva jeg gjorde nylig. Det har trolig blitt gjort andre steder bedre, men det virker ganske ren og gjenbrukbare.

Jeg har et verktøy metode som ser slik ut:

    public delegate void WorkMethod();

    static public void DoAndRetry(WorkMethod wm, int maxRetries)
    {
        int curRetries = 0;
        do
        {
            try
            {
                wm.Invoke();
                return;
            }
            catch (Exception e)
            {
                curRetries++;
                if (curRetries > maxRetries)
                {
                    throw new Exception("Maximum retries reached", e);
                }
            }
        } while (true);
    }

Så i søknaden min, jeg bruker c # 's Lamda uttrykk syntaks for å holde ting ryddig:

Utility.DoAndRetry( () => ie.GoTo(url), 5);

Dette kaller min metode og prøver opp til 5 ganger. På det femte forsøket, blir den opprinnelige unntak rethrown innsiden av et nytt forsøk unntak.

Svarte 13/09/2010 kl. 02:25
kilden bruker

stemmer
2

Du kan også bruke en mer OO tilnærming:

  • Lag en basisklasse som gjør feilbehandling og kaller en abstrakt metode for å utføre betongarbeidet. (Mal Metode mønster)
  • Lag konkrete klasser for hver operasjon.

Dette har fordelen av å navngi hver type operasjon du utfører og gir deg en Command mønster - virksomhet er omarbeidet som objekter.

Svarte 07/08/2008 kl. 11:30
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more