Этот вопрос поднимался много раз, но я хотел бы задать его еще раз, потому что я прочитал некоторые вещи, которые мне не кажутся правильными (возможно, потому, что один из них связан с .NET CF) и я прошу подтвердить конкретный подход, который я считаю разумным, и буду признателен за любые ваши отзывы.
Во всяком случае, ситуация очень похожа на все остальные - я хочу обрабатывать ошибки, возникающие из потока. В настоящее время код, который у меня работает, работает нормально, потому что я генерирую исключения из потока, но я использую Invoke, а не BeginInvoke.
В этот момент вы, вероятно, задаетесь вопросом: «Зачем ему создавать поток, а затем вызывать Invoke? Почему бы просто не вызвать функцию?». Проблема в том, что я хочу предоставить вызывающей стороне гибкость с помощью параметра, который определяет, должна ли операция быть синхронной или асинхронной.
В качестве теста я проверил его в асинхронном режиме работы, и, как и ожидалось, он молча завершается сбоем, и приложение умирает в отладчике в момент, когда исключение выдается из рабочего потока.
Чтобы убедиться, что у меня есть общее представление о поведении исключений в потоках, а также о том, что опровергает утверждение в этом вопросе о SO (по крайней мере, до .NET 3.5), я написал тестовый код в приложении WPF:
код удален
Так что, похоже, не должно быть проблем с обработкой событий в главном потоке, которые происходят из другого потока.
При условии, что вы согласны с моими тестами, приведенными выше, мой вопрос заключается просто в следующем: является ли приемлемой практика писать мой метод, который предлагает как синхронизацию, так и асинхронное поведение, когда вся бизнес-логика заключена в блок try / catch? Внутренние ошибки попадают в ловушку внутри потока, и если это синхронизирующий вызов, просто сгенерируйте исключение, а если это асинхронный вызов, просто вызовите событие? В приведенном выше примере кода я также выбрасываю исключение после вызова события. Я не уверен, если или почему это вызовет у меня какие-либо проблемы.
Pseudo-pseudocode:
TestFunc(async);
private TestFunc(bool async)
{
try {
throw new MyAppException("error occurred.");
} catch(MyAppException ex) {
async ? RaiseErrorEvent : throw;
}
}
UPDATE
Хорошо, как сказал Ганс, это вызовет проблемы, независимо от того, что если я сгенерирую исключение из потока - точка. Я смог проверить этот случай и, конечно же, исключение выдается, и если вы нажмете F5, оно просто будет выдано снова и снова и никогда не завершит поток. Я не понимаю этого конкретного поведения - это просто, как он работает при запуске через отладчик? Я предполагаю, что это означает, что я должен проверить, называется ли метод синхронизированным или асинхронным. Если синхронизировать, выкинь ошибку. Если асинхронно, поднять событие.
Возможно, лучший способ сделать это - заставить клиента всегда обрабатывать ошибки с событиями, а не перехватывать исключения? У кого-нибудь есть мысли по поводу этого подхода?