Исключения в асинхронном цикле - PullRequest
1 голос
/ 05 января 2012

У меня есть что-то вроде этого:

void GenerateReports() {
    foreach (var employee in employees) {
        GenerateReport(employee);
    }
}

GenerateReport занимает много времени, и я не хочу блокировать свой поток пользовательского интерфейса, поэтому я запускаю этот метод в отдельном потоке.

Однако, GenerateReport иногда выдает исключение. Я хочу обработать каждое исключение в моем потоке пользовательского интерфейса и перейти к следующему сотруднику. Как мне это сделать при генерации отчетов асинхронно? Если я добавлю GenerateReport в другой поток, цикл foreach будет очень быстрым, и все отчеты будут созданы одновременно:

void GenerateReports() {
    foreach (var employee in employees) {
        GenerateReportAsync(employee, OnDoneCallback); // returns immediately
    }
}

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

Ответы [ 3 ]

1 голос
/ 05 января 2012

Я бы поставил try-catch вокруг частей вашего метода, которые будут выдавать ошибки, и, если вы хотите, чтобы они возвращались в поток пользовательского интерфейса, создайте метод, который вы можете передать в качестве обратного вызова:

void OnErrorCallback(Exception ex)
{
   if(InvokeRequired)
   {
      //bring method execution up to the UI thread
      this.Invoke((MethodInvoker)(()=>OnErrorCallback(ex)));
      return;
   }

   //handle the exception, with access to UI components.
}

void GenerateReports() {
    foreach (var employee in employees) {
        GenerateReportAsync(employee, OnDoneCallback); // returns immediately
    }
}

void GenerateReportAsync(Employee employee, AsyncCallback OnDoneCallback)
{
    //Delegate.BeginInvoke takes all parameters of the delegate, plus 
    //something to call when done, PLUS a state object that can be 
    //used to monitor work in progress (null is fine too).
    GenerateReport.BeginInvoke(employee, OnErrorCallback, OnDoneCallback, null);
}

void GenerateReport(Employee employee, Action<Exception> errorCallback)
{
    try
    {
        //do your dirty work
    }
    catch(Exception ex)
    {
        //execute the delegate, which will re-execute itself on the UI 
        //thread if necessary. You're basically rethrowing the exception 
        //"sideways" to the UI thread, rather than up the call stack.
        errorCallback(ex);
    }
}
1 голос
/ 05 января 2012

если вы используете BackGround Worker для работы с потоками, вы можете использовать его метод BackgroundWorker.ReportProgress, подробности здесь . Чтобы отправить данные обратно в ваш поток пользовательского интерфейса.

0 голосов
/ 05 января 2012

Вы можете использовать фоновый рабочий класс. Что-то вроде этого.

void GenerateReports()
{
var backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += ((s, e) =>
    {
        // time consuming function
        foreach (var employee in employees)
            GenerateReport(employee);
    }); 

backgroundWorker.RunWorkerCompleted += ((s, e) =>
    {
        //do something
    });

backgroundWorker.RunWorkerAsync();
} 

delegate void Update(Employee employee);
static void GenerateReport(Employee employee)
{
    if (this.InvokeRequired)
    {
        Update updaterDelegate = new Update(GenerateReport);
        this.Invoke(updaterDelegate, new object[] { employee });
    }
    else
        GenerateReport(employee)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...