Как реализовать логику повтора с помощью параллельной библиотеки задач (TPL)

Возможный дубликат:
Повторить задачу несколько раз на основе пользовательского ввода в случае исключения в задаче

Я ищу способ реализовать логику повтора в TPL. Я хотел бы иметь общую функцию/класс, которая сможет вернуть задачу, которая выполнит данное действие, и в случае исключения повторит задачу, вплоть до заданного количества повторов. Я попытался сыграть с ContinueWith и вызвать обратный вызов для создания новой задачи в случае исключения, но, похоже, он будет работать только для фиксированного количества попыток. Любые предложения?

    private static void Main()
    {
        Task<int> taskWithRetry = CreateTaskWithRetry(DoSometing, 10);
        taskWithRetry.Start();
        // ...

    }

    private static int DoSometing()
    {
        throw new NotImplementedException();
    }

    private static Task<T> CreateTaskWithRetry<T>(Func<T> action, int retryCount)
    {

    }

Ответ 1

Любая причина делать что-то особенное с TPL? Почему бы просто не сделать обертку для Func<T> себя?

public static Func<T> Retry(Func<T> original, int retryCount)
{
    return () =>
    {
        while (true)
        {
            try
            {
                return original();
            }
            catch (Exception e)
            {
                if (retryCount == 0)
                {
                    throw;
                }
                // TODO: Logging
                retryCount--;
            }
        }
    };
}

Обратите внимание, что вы можете добавить метод ShouldRetry(Exception), чтобы некоторые исключения (например, отмена) прерывались без повторения.

Ответ 2

private static Task<T> CreateTaskWithRetry<T>(Func<T> action, int retryCount)
{
    Func<T> retryAction = () =>
    {
        int attemptNumber = 0;
        do
        {
            try
            {
                attemptNumber++;
                return action();
            }
            catch (Exception exception) // use your the exception that you need
            {
                // log error if needed
                if (attemptNumber == retryCount)
                    throw;
            }
        }
        while (attemptNumber < retryCount);

        return default(T);
    };

    return new Task<T>(retryAction);
}