我的方法之一(Method1
)產生了一個新的線程。 該線程執行一個方法(Method2
),並在執行過程中引發異常。 我需要的調用方法是異常信息(Method1
)捕捉異常拋出不同的線程
有什麼方法我能趕上在Method1
這個例外是在Method2
拋出?
我的方法之一(Method1
)產生了一個新的線程。 該線程執行一個方法(Method2
),並在執行過程中引發異常。 我需要的調用方法是異常信息(Method1
)捕捉異常拋出不同的線程
有什麼方法我能趕上在Method1
這個例外是在Method2
拋出?
在.NET 4及以上,您可以使用Task<T>
類,而不是創建新的線程。然後,您可以在任務對象上使用.Exceptions
屬性來獲取異常。 有2種方式來做到這一點:
在一個單獨的方法://你處理一些任務的線程
class Program
{
static void Main(string[] args)
{
Task<int> task = new Task<int>(Test);
task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
task.Start();
Console.ReadLine();
}
static int Test()
{
throw new Exception();
}
static void ExceptionHandler(Task<int> task)
{
var exception = task.Exception;
Console.WriteLine(exception);
}
}
例外相同的方法://你處理例外在呼叫者的線程
class Program
{
static void Main(string[] args)
{
Task<int> task = new Task<int>(Test);
task.Start();
try
{
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();
}
static int Test()
{
throw new Exception();
}
}
請注意,您得到的例外是AggregateException
。所有真正的例外均可通過ex.InnerExceptions
屬性獲得。
在.NET 3.5您可以使用下面的代碼:
在孩子的線程//你的過程異常
class Program
{
static void Main(string[] args)
{
Exception exception = null;
Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), Handler));
thread.Start();
Console.ReadLine();
}
private static void Handler(Exception exception)
{
Console.WriteLine(exception);
}
private static void SafeExecute(Action test, Action<Exception> handler)
{
try
{
test.Invoke();
}
catch (Exception ex)
{
Handler(ex);
}
}
static void Test(int a, int b)
{
throw new Exception();
}
}
或者//你處理例外來電者的線程
class Program
{
static void Main(string[] args)
{
Exception exception = null;
Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), out exception));
thread.Start();
thread.Join();
Console.WriteLine(exception);
Console.ReadLine();
}
private static void SafeExecute(Action test, out Exception exception)
{
exception = null;
try
{
test.Invoke();
}
catch (Exception ex)
{
exception = ex;
}
}
static void Test(int a, int b)
{
throw new Exception();
}
}
您無法捕獲Method1中的異常。但是,您可以在Method2中捕獲異常並將其記錄到原始執行線程可以讀取和使用的變量中。
感謝您的回覆。所以如果Method1是Class1的一部分,並且在該類中有一個類型爲Exception的變量。每當Method2引發異常時,它也會在Class1中設置該異常變量。這聽起來像一個公平的設計?有沒有處理這種情況的最佳實踐方法? – 2011-05-12 20:09:55
正確,您只需存儲該異常並稍後訪問它。將來運行的方法(尤其是Method2完成時的回調函數)然後重新拋出異常,就好像它們自己造成了異常一樣,但這確實取決於您想要的結果。 – ermau 2011-05-12 20:14:12
到不同線程之間共享數據的最簡單的方法是shared data
如下(一些是僞代碼):
class MyThread
{
public string SharedData;
public void Worker()
{
...lengthy action, infinite loop, etc...
SharedData = "whatever";
...lengthy action...
return;
}
}
class Program
{
static void Main()
{
MyThread m = new MyThread();
Thread WorkerThread = new Thread(m.Worker);
WorkerThread.Start();
loop//or e.g. a Timer thread
{
f(m.SharedData);
}
return;
}
}
可以讀取關於在this nice introduction about multithreading該方法中,然而,我優選閱讀有關這個在O'Reilly book C# 3.0 in a nutshell
中由Albahari(2007)兄弟提供,它也可以在Google Books上免費訪問,就像本書的較新版本一樣,因爲它還包括線程池,前景與後臺線程等等,示例代碼。 (免責聲明:我擁有本書的一個破舊的副本)
如果您正在製作WinForms應用程序,使用共享數據尤其方便,因爲WinForm控件不是線程安全的。使用回調將工作線程中的數據傳遞迴WinForm控件,主UI線程需要使用難以編碼的代碼Invoke()
來使該控件成爲線程安全的。改爲使用共享數據,並使用單線程System.Windows.Forms.Timer
和短時間Interval
,例如0.2秒,您可以輕鬆地將信息從工作線程發送到控件,而無需使用Invoke
。
對不起,但我忘了提及我正在使用.NET 3.5。根據我的理解任務是4.0的東西? – 2011-05-12 20:10:38
@SilverlightStudent好吧,我剛更新了我的答案以滿足您的要求。 – oxilumin 2011-05-12 20:30:18
@oxilumin:非常感謝,非常感謝。還有一個後續問題。如果你的Test()方法也有一些參數,那麼你將如何修改這些參數的SafeExecute方法? – 2011-05-13 14:34:50