Het verminderen van dubbele error handling code in C #?

stemmen
32

Ik heb nooit helemaal tevreden met de manier waarop exception handling werken geweest, er is veel uitzonderingen en proberen / catch brengt aan de tafel (stack afwikkelen, enz.), Maar het lijkt een groot deel van de OO model in het proces te doorbreken.

Hoe dan ook, hier is het probleem:

Laten we zeggen dat je wat klasse die wraps of omvat een netwerk file IO operaties (bijvoorbeeld lezen en schrijven naar een bestand op een bepaald UNC-pad ergens). Om verschillende redenen waarom je niet wil dat die IO operaties te mislukken, dus als je detecteren dat ze niet je ze opnieuw proberen en je opnieuw proberen te houden totdat ze slagen of u een time-out te bereiken. Ik heb al een geschikte RetryTimer klasse die ik instantiëren en gebruiken om de huidige thread pogingen tussen slapen en bepalen wanneer de time-outperiode is verstreken, etc.

Het probleem is dat u een bos van IO operaties in verschillende methoden van deze klasse, en je moet elk van hen te verpakken in try-catch / retry logica.

Hier is een voorbeeld code fragment:

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

Dus, hoe voorkom je het dupliceren van het grootste deel van deze code voor elk bestand IO bedrijf gedurende het hele klas? Mijn oplossing was om anonieme delegeren blokken en een enkele methode in de klasse waarin de afgevaardigde blok doorgegeven om het uitgevoerde gebruiken. Dit liet me om dingen te doen als dit in andere methoden:

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

Ik vind dit een beetje, maar het laat veel te wensen over. Ik wil graag horen hoe andere mensen dit soort problemen zou oplossen.

De vraag is gesteld op 04/08/2008 om 20:21
bron van user
In andere talen...                            


4 antwoorden

stemmen
13

Dit ziet eruit als een uitstekende gelegenheid om een kijkje te Aspect Oriented Programming hebben. Hier is een goed artikel over AOP in .NET . Het algemene idee is dat u de cross-functionele zorg (dwz Retry gedurende x uur) in een aparte klasse zou halen en dan zou je alle methoden die moeten hun gedrag op die manier aan te passen annoteren. Hier is hoe het eruit zou kunnen zien (met een mooie extension method op Int32)

[RetryFor( 10.Hours() )]
public void DeleteArchive()
{
  //.. code to just delete the archive
}
antwoordde op 05/08/2008 om 10:43
bron van user

stemmen
4

Ik vroeg me af, wat voel je je methode te wensen overlaat? Je kon de anonieme deelnemer met een te vervangen .. genoemd? afgevaardigde, zoiets als

    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" );
    }
antwoordde op 04/08/2008 om 21:07
bron van user

stemmen
2

Hier is wat ik deed onlangs. Het is waarschijnlijk beter elders gedaan, maar het lijkt vrij schoon en herbruikbaar.

Ik heb een hulpprogramma methode die er als volgt uitziet:

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

Toen in mijn toepassing, gebruik ik c # 's Lamda expressiesyntaxis om dingen netjes te houden:

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

Dit vraagt ​​mijn methode en probeert ze opnieuw tot 5 keer. Op de vijfde poging, wordt de oorspronkelijke uitzondering rethrown binnenkant van een retry uitzondering.

antwoordde op 13/09/2010 om 03:25
bron van user

stemmen
2

U kunt ook gebruik maken van een meer OO aanpak:

  • Maak een basisklasse dat de foutafhandeling doet en roept een abstracte methode om de betonnen werk uit te voeren. (Template methode patroon)
  • Maak concrete klassen voor elke bewerking.

Dit heeft het voordeel dat het benoemen van elk type bewerking die u uitvoert en geeft u een Command patroon - activiteiten zijn voorgesteld als objecten.

antwoordde op 07/08/2008 om 12:30
bron van user

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