captura exceção que é lançada em um segmento diferente
110
Um dos meus métodos ( Method1) gera um novo thread. Esse thread executa um método ( Method2) e durante a execução uma exceção é lançada. Preciso obter essas informações de exceção no método de chamada ( Method1)
Há alguma maneira de detectar essa exceção Method1que é lançada Method2?
No .NET 4 e superior, você pode usar a Task<T>classe em vez de criar um novo thread. Em seguida, você pode obter exceções usando a .Exceptionspropriedade em seu objeto de tarefa. Existem 2 maneiras de fazer isso:
Em um método separado: // Você processa a exceção no thread de alguma tarefa
Desculpe, mas esqueci de mencionar que estou usando o .NET 3.5. Pelo que entendi, a tarefa é 4.0 coisa?
Silverlight Student
2
@SilverlightStudent Ok, acabei de atualizar minha resposta para atender às suas necessidades.
oxilumina
@oxilumin: Obrigado e muito apreciado. Mais uma pergunta de acompanhamento. Se o seu método Test () também aceita alguns argumentos, como você modificará o método SafeExecute para esses argumentos?
Silverlight Student
2
@SilverlightStudent Neste caso, passarei um lambda em vez de Test. Como() => Test(myParameter1, myParameter2)
oxilumina
2
@SilverlightStudent: Atualizado.
oxilumina
9
Você não pode capturar a exceção no Método1. Você pode, no entanto, capturar a exceção no Método2 e gravá-la em uma variável que o encadeamento original de execução pode ler e trabalhar.
Obrigado pela sua resposta. Portanto, If Method1 é parte de Class1 e eu tenho uma variável do tipo Exception nessa classe. Sempre que Method2 lança uma exceção, ele define essa variável de exceção em Class1 também. Parece um design justo? Existe alguma forma de prática recomendada de lidar com esse cenário?
Silverlight Student
Correto, basta armazenar a exceção e acessá-la mais tarde. Não é incomum que métodos executados no futuro (especialmente callbacks para quando o Método2 for concluído) relançar essa exceção como se eles próprios a tivessem causado, mas isso realmente depende do que você deseja.
ermau
0
O método mais simples para compartilhar dados entre diferentes threads é shared datao seguinte (alguns são pseudocódigos):
classMyThread{publicstringSharedData;publicvoidWorker(){...lengthy action, infinite loop, etc...SharedData="whatever";...lengthy action...return;}}classProgram{staticvoidMain(){MyThread m =newMyThread();ThreadWorkerThread=newThread(m.Worker);WorkerThread.Start();
loop//or e.g. a Timer thread{
f(m.SharedData);}return;}}
Você pode ler sobre esse método nesta bela introdução sobre multithreading , no entanto, eu preferi ler sobre isso no O'Reilly book C# 3.0 in a nutshell, dos irmãos Albahari (2007), que também pode ser acessado gratuitamente no Google Livros, assim como a versão mais recente do livro, porque também cobre o pool de threads, threads em primeiro plano versus segundo plano, etc etc, com um código de exemplo simples e agradável. (Isenção de responsabilidade: eu possuo uma cópia desgastada deste livro)
No caso de você estar fazendo um aplicativo WinForms, o uso de dados compartilhados é especialmente útil, porque os controles do WinForm não são seguros para threads. Usando um retorno de chamada para passar dados do thread de trabalho de volta para um controle WinForm, o thread de IU principal precisa de um código feio Invoke()para tornar esse controle thread-safe. Usando dados compartilhados, e o thread único System.Windows.Forms.Timer, com um curto Intervalde, digamos, 0,2 segundos, você pode facilmente enviar informações do thread de trabalho para o controle sem Invoke.
Eu tive um problema específico em que queria usar itens, contendo controles, de um conjunto de testes de integração, então tive que criar um thread STA. O código que obtive é o seguinte, colocado aqui no caso de outros terem o mesmo problema.
publicBoolean?Dance(String name){// Already on an STA thread, so just go for itif(Thread.CurrentThread.GetApartmentState()==ApartmentState.STA)returnDanceSTA(name);// Local variable to hold the caught exception until the caller can rethrowException lException =null;Boolean? lResult =null;// A gate to hold the calling thread until the called thread is donevar lGate =newManualResetEvent(false);var lThreadStart =newThreadStart(()=>{try{
lResult =DanceSTA(name);}catch(Exception ex){
lException = ex;}
lGate.Set();});var lThread =newThread(lThreadStart);
lThread.SetApartmentState(ApartmentState.STA);
lThread.Start();
lGate.WaitOne();if(lException !=null)throw lException;return lResult;}publicBoolean?DanceSTA(String name){...}
Esta é uma colagem direta do código no estado em que se encontra. Para outros usos, eu recomendaria fornecer uma ação ou função como parâmetro e invocá-la no thread em vez de codificar permanentemente o método chamado.
Test
. Como() => Test(myParameter1, myParameter2)
Você não pode capturar a exceção no Método1. Você pode, no entanto, capturar a exceção no Método2 e gravá-la em uma variável que o encadeamento original de execução pode ler e trabalhar.
fonte
O método mais simples para compartilhar dados entre diferentes threads é
shared data
o seguinte (alguns são pseudocódigos):Você pode ler sobre esse método nesta bela introdução sobre multithreading , no entanto, eu preferi ler sobre isso no
O'Reilly book C# 3.0 in a nutshell
, dos irmãos Albahari (2007), que também pode ser acessado gratuitamente no Google Livros, assim como a versão mais recente do livro, porque também cobre o pool de threads, threads em primeiro plano versus segundo plano, etc etc, com um código de exemplo simples e agradável. (Isenção de responsabilidade: eu possuo uma cópia desgastada deste livro)No caso de você estar fazendo um aplicativo WinForms, o uso de dados compartilhados é especialmente útil, porque os controles do WinForm não são seguros para threads. Usando um retorno de chamada para passar dados do thread de trabalho de volta para um controle WinForm, o thread de IU principal precisa de um código feio
Invoke()
para tornar esse controle thread-safe. Usando dados compartilhados, e o thread únicoSystem.Windows.Forms.Timer
, com um curtoInterval
de, digamos, 0,2 segundos, você pode facilmente enviar informações do thread de trabalho para o controle semInvoke
.fonte
Eu tive um problema específico em que queria usar itens, contendo controles, de um conjunto de testes de integração, então tive que criar um thread STA. O código que obtive é o seguinte, colocado aqui no caso de outros terem o mesmo problema.
Esta é uma colagem direta do código no estado em que se encontra. Para outros usos, eu recomendaria fornecer uma ação ou função como parâmetro e invocá-la no thread em vez de codificar permanentemente o método chamado.
fonte