Reducerea duplicat cod de eroare de manipulare în C #?

voturi
32

Nu am fost niciodată complet fericit cu modul în care lucrările de manipulare excepție, există o mulțime de excepții și să încercați / captură aduce la masa (stiva de derulare, etc), dar se pare să rupă o mulțime de modelul OO în proces.

Oricum, aici e problema:

Să presupunem că aveți unele clasă care se înfășoară sau include operațiuni de fișier IO în rețea (de exemplu, citirea și la unele fișier la un anumit cale UNC undeva). Din diverse motive, nu doriți ca aceste operațiuni IO să eșueze, așa că, dacă detectează faptul că nu reușesc să le încercați din nou și păstrați-le să încercați din nou până când reușesc să ajungă sau un timeout. Am deja o clasă RetryTimer convenabil pe care le pot instantiate și de a folosi pentru a dormi firul de curent între reíncercări și de a determina în cazul în care perioada de inactivitate a trecut, etc.

Problema este că aveți o grămadă de operații IO în mai multe metode din această clasă, și trebuie să infasoara fiecare dintre ele în logica try-catch / reîncerca.

Iată un fragment de cod de exemplu:

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

Deci, cum puteți evita duplicarea cea mai mare parte de acest cod pentru fiecare fișier de operare IO întreaga clasă? Soluția mea a fost de a utiliza blocuri delegatului anonime și o singură metodă din clasa care a executat blocul delegat a trecut la ea. Acest lucru mi-a permis să fac lucruri de genul asta în alte metode:

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

Îmi place acest lucru oarecum, dar lasă mult de dorit. Aș vrea să aud cum alți oameni ar rezolva acest tip de probleme.

Întrebat 04/08/2008 la 20:21
sursa de către utilizator
În alte limbi...                            


4 răspunsuri

voturi
13

Acest lucru arata ca o oportunitate excelentă de a avea o privire la Aspect Oriented Programming. Aici este un articol bun pe AOP în .NET . Ideea generală este că ai extrage preocuparea eco-funcționale ( de exemplu , reîncercați x ore) într - o clasă separată și apoi ai adnota orice metode care trebuie să -și modifice comportamentul în acest fel. Iată cum ar putea arăta (cu o metodă de extensie de frumos pe int32)

[RetryFor( 10.Hours() )]
public void DeleteArchive()
{
  //.. code to just delete the archive
}
Publicat 05/08/2008 la 10:43
sursa de către utilizator

voturi
4

Doar întrebam, ce vă simțiți metoda lasă de dorit? Ați putea înlocui delegatul anonim cu un nume ..? delegat, ceva de genul

    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" );
    }
Publicat 04/08/2008 la 21:07
sursa de către utilizator

voturi
2

Iată ce am făcut recent. Acesta a fost, probabil, mai bine făcut în altă parte, dar se pare destul de curat și reutilizabile.

Am o metodă de utilitate care arată astfel:

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

Apoi, în cererea mea, am folosi sintaxa C # 's Lamda expresie pentru a menține lucrurile în ordine:

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

Aceasta numește metoda mea și reîncearcă de până la 5 ori. La a cincea încercare, excepția original este rethrown în interiorul unei excepții reîncerca.

Publicat 13/09/2010 la 03:25
sursa de către utilizator

voturi
2

Ai putea folosi, de asemenea, o abordare mai OO:

  • Creați o clasă de bază care face manipularea de eroare și solicită o metodă abstractă pentru a efectua lucrările de beton. (Model Metoda Template)
  • Crearea clase concrete pentru fiecare operațiune.

Acest lucru are avantajul de a numi fiecare tip de operațiune efectuați și vă oferă un model de comandă - operațiuni au fost reprezentate ca obiecte.

Publicat 07/08/2008 la 12:30
sursa de către utilizator

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