Уменьшение дублирования кода обработки ошибок в C #?

голоса
32

Я никогда не был полностью доволен тем, как обработки исключительных работами, есть много исключений и попробовать / поймать приводит к таблице (стек разматывания и т.д.), но это, кажется, сломать много модели OO в этом процессе.

Во всяком случае, вот проблема:

Скажем, у вас есть класс, который оборачивает или включает в себя сетевые файловые операции ввода-вывода (например, чтение и запись в файл какой-то на каком-то конкретном пути UNC где-то). По разным причинам вы не хотите, чтобы эти операции ввода-вывода, чтобы потерпеть неудачу, поэтому, если вы обнаружили, что они не вы повторить их, и вы держите их, пока Повторная попытка им не удастся или достичь тайм-аут. У меня уже есть удобный класс RetryTimer, который я могу создать экземпляр и использовать спать текущий поток между повторными и определить, когда время ожидания истекло, и т.д.

Проблема заключается в том, что у вас есть куча операций ввода-вывода в несколько методов этого класса, и вам нужно обернуть каждый из них в примерочных поймать / повторов логики.

Вот пример фрагмента кода:

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

Итак, как же избежать дублирования большая часть этого кода для каждого файла операции ввода-вывода по всему классу? Мое решение было использовать анонимный делегат блоки и один метод в классе, который выполняется делегат блок, переданный ему. Это позволило мне делать такие вещи, как это в других методах:

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

Мне нравится это несколько, но она оставляет желать лучшего. Я хотел бы услышать, как другие люди будут решать такого рода проблемы.

Задан 04/08/2008 в 20:21
источник пользователем
На других языках...                            


4 ответов

голоса
13

Это выглядит как отличная возможность взглянуть на Аспект - ориентированное программирование. Вот хорошая статья на АОП в .NET . Основная идея заключается в том , что вы хотите извлечь межфункциональную озабоченность (т.е. Retry для й часов) в отдельный класс , а затем вы аннотировать любые методы , которые должны изменить свое поведение таким образом. Вот как это может выглядеть (с хорошим методом расширения на Int32)

[RetryFor( 10.Hours() )]
public void DeleteArchive()
{
  //.. code to just delete the archive
}
Ответил 05/08/2008 d 10:43
источник пользователем

голоса
4

Просто интересно, что вы чувствуете, что ваш метод оставляет желать лучшего? Можно заменить анонимный делегат с .. с именем? Делегат, что-то вроде

    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" );
    }
Ответил 04/08/2008 d 21:07
источник пользователем

голоса
2

Вот что я сделал в последнее время. Это, вероятно, было сделано в другом месте лучше, но это, кажется, довольно чистый и многоразовые.

У меня есть служебный метод, который выглядит следующим образом:

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

Тогда в моем приложении я использую синтаксис Lamda выражение С #, чтобы держать вещи аккуратно:

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

Это вызывает мой метод и повторит до 5 раз. На пятой попытки, оригинальное исключение вызвано повторно внутри исключения повторных попыток.

Ответил 13/09/2010 d 03:25
источник пользователем

голоса
2

Кроме того, можно использовать более ОО подход:

  • Создать базовый класс, который делает обработку ошибок и вызывает абстрактный метод для выполнения конкретной работы. (Метод шаблона шаблон)
  • Создание конкретных классов для каждой операции.

Это имеет преимущество именования каждого типа операции, которую вы выполняете, и дает вам шаблон Command - операции были представлены в виде объектов.

Ответил 07/08/2008 d 12:30
источник пользователем

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